Déterminer quelle valeur représente quelle direction dans un chemin

10

Modification importante: auparavant, il y avait une valeur incorrecte dans l'exemple 1. Elle a été corrigée.

Vous obtenez un tableau à deux dimensions dans lequel chaque cellule contient l'une des quatre valeurs.

Exemples:

1 2 2 2 2 1        @ . .        X X V
1 3 1 4 1 4        e . @        I C V
2 3 1 3 4 2        H H @        X I V
1 4 4 2 1 3                     V C C
2 2 2 3 2 3                     X X X

Les quatre valeurs représentent des flèches directionnelles (haut, bas, gauche et droite), bien que vous ne sachiez pas quelle valeur représente quelle direction.

Les flèches directionnelles forment un chemin ininterrompu qui inclut toutes les cellules du tableau, bien que vous ne sachiez pas où se trouvent les points de début ou de fin.

Écrivez du code qui détermine dans quelle direction chacune des quatre valeurs représente et où se trouvent les points de début et de fin.

Une valeur de retour acceptable pour un tableau contenant les valeurs A, B, C et D serait quelque chose comme:

{ up: A, down: C, left: D, right: B, start: [2, 0], end: [4, 2] }

Parce que vous pouvez parcourir le chemin dans les deux sens (du début à la fin et de la fin au début), il y aura toujours plus d'une solution correcte et il peut y en avoir plus de deux. Supposons que les entrées que vous recevez (comme dans les exemples ci-dessus) aient toujours au moins une solution correcte. Dans les cas où il existe plusieurs solutions correctes, le retour d'une seule des solutions correctes est suffisant.

Le code le plus court gagne. Je choisirai le gagnant après 7 jours ou 24 heures sans nouvelle soumission, selon la première éventualité.

J'inclus des solutions aux exemples ci-dessus, mais je vous encourage à ne les vérifier qu'une fois que vous avez écrit votre code:

Une:

{haut: 3, bas: 1, gauche: 4, droite: 2, début: [0,0], fin: [2,5]}

Deux:

{haut: '@', bas: 'e', ​​gauche: '.', droite: 'H', début: [1,1], fin: [0,0]}

Trois:

{haut: 'I', bas: 'V', gauche: 'C', droite: 'X', début: [0,2], fin: [4,2]}

jawns317
la source
1
"vous pouvez parcourir le chemin dans les deux sens" - si les directions sont absolues et non relatives, ce n'est pas vrai. Les directions sont-elles absolues ou relatives? En outre, le début et la fin sont-ils connus pour être en dehors du tableau?
John Dvorak
@JanDvorak Les points de début et de fin sont des cellules du tableau. Quant aux directions, supposons qu'elles indiquent toujours un mouvement dans une cellule adjacente (nord, sud, est ou ouest).
jawns317
Dans ce cas, il n'est pas possible de parcourir un chemin vers l'arrière. Je ne vois aucune garantie qu'il y aura toujours plus d'une solution.
John Dvorak
1
Si nous «supposons qu'ils indiquent toujours un mouvement dans une cellule adjacente», votre deuxième exemple est-il toujours valable? Il me manque peut-être quelque chose, mais il semble que @ ne puisse être l'une des quatre directions sans sortir "des limites".
Nick Sarabyn
1
L'exemple 1 n'a pas de solution.
DavidC

Réponses:

6

C #

EDIT: correction d'une division et d'un formatage. Et ajouté la classe d'assistance.

Ceci est le code golfé, 807 caractères

class M{public int c,x,y,u;}
void G(string[] z){
M K;int[]x={0,0,-1,1},y={-1,1,0,0},I={0,0,0,0};
string[]T={"Up","Down","Left","Right"};
int X,Y,R,n=0,H=z.Length,W=z[0].Length;W-=W/2;var D= string.Join(" ", z).Where(c=>c!=' ').Select(c=>new M(){c=c,x=n%W,y=n++/W}).ToList();n=0;var S=D.GroupBy(k=>k.c).ToDictionary(k=>k.Key,k =>n++);
for(;I[0]<4;I[0]++)for(I[1]=0;I[1]<4;I[1]++)for(I[2]=0;I[2]<4;I[2]++)for(I[3]=0;I[3]<4;I[3]++){
if ((1<<I[0]|1<<I[1]|1<<I[2]|1<<I[3])!=15)continue;
foreach (var Q in D){D.ForEach(p=>p.u=-1);R=1;K=Q;j:if((X=K.x+x[n=I[S[K.c]]])>=0&&X<W&&(Y=K.y+y[n])>=0&&Y<H&&(K=D[X+Y*W]).u<0){
K.u=1;if(++R==D.Count){Console.WriteLine("{4} Start({0}:{1}) End({2}:{3})",Q.x,Q.y,K.x,K.y,string.Join(", ",S.Select(k=>string.Format("{1}: '{0}'",(char)k.Key,T[I[k.Value]])).ToArray()));return;}goto j;}}}
}    

Résultats pour les trois cas de test:

Bas: '1', Droite: '2', Haut: '3', Gauche: '4' Début (0: 0) Fin (5: 2)
Haut: '@', Gauche: '.', Bas: ' e ', Droite:' H 'Début (1: 1) Fin (0: 0)
Droite:' X ', Bas:' V ', Haut:' I ', Gauche:' C 'Début (0: 2) Fin (2: 4)

C'est le code brut sans "golf", près de 4 000 caractères:

class Program
{
    static string[] input1 =  { "1 2 2 2 2 1",
               "1 3 4 4 1 4",       
               "2 3 1 3 4 2",
               "1 4 4 2 1 3",       
               "2 2 2 3 2 3"};

    static string[] input2 =  { "@ . .",
                                "e . @",       
                                "H H @",
               };

    static string[] input3 =  { "0 0 1",
                                "0 0 1",       
                                "3 2 2",
               };

    static void Main(string[] args)
    {
        Resolve(input1);
        Resolve(input2);
        Resolve(input3);
        Console.ReadLine();
    }


    class N { public int c; public int x, y, i, u; }

    static void Resolve(string[] input)
    {
        int[] ox = { -1, 1, 0, 0 }, oy = { 0, 0, -1, 1 }, I = { 0, 0, 0, 0 };
        string[] TXT = { "Left", "Right", "Up", "Down" };
        int X, Y, R, n = 0, H = input.Length, W = input[0].Length;
        W -= W / 2;
        N K = null;
        var data = string.Join(" ", input).Where(c => c != ' ').Select(c => new N() { c = c, x = (n % W), y = (n / W), i = n++, u = -1 }).ToList();
        n = 0;
       var S = data.GroupBy(k => k.c).ToDictionary(k => k.Key, k => n++);

        for (; I[0] < 4; I[0]++)
            for (I[1] = 0; I[1] < 4; I[1]++)
                for (I[2] = 0; I[2] < 4; I[2]++)
                    for (I[3] = 0; I[3] < 4; I[3]++)
                    {
                        if (((1 << I[0]) | (1 << I[1]) | (1 << I[2]) | (1 << I[3])) != 15) continue;
                        foreach(var Q in data)
                        {
                            data.ForEach(p => p.u = -1);
                            R = 0;
                            K = Q;
                            while (K != null)
                            {
                                n = I[S[K.c]];
                                X = K.x + ox[n];
                                Y = K.y + oy[n];
                                if (X >= 0 && X < W && Y >= 0 && Y < H)
                                {
                                    n = X + Y * W;
                                    if (data[n].u < 0)
                                    {
                                         data[n].u = K.i;
                                         K = data[n];
                                        R++;
                                        if (R == data.Count - 1)
                                        {
                                            Console.WriteLine();
                                            Console.WriteLine("Start({0}:{1}) End({2}:{3})", Q.x, Q.y, K.x, K.y);
                                            Console.WriteLine(string.Join(", ", S.Select(k => string.Format("'{0}': {1}", (char)k.Key, TXT[I[k.Value]])).ToArray()));
                                            Action<N> Write = null;
                                            Write = (k) =>
                                             {
                                                 if (k.u != -1)
                                                 {
                                                     Write(data[k.u]);
                                                 }
                                                 Console.Write(string.Format("({0}:{1}){2}", k.x, k.y, k == K ? "\n" : " => "));
                                             };

                                            Write(K);
                                            return;
                                        }
                                        continue;
                                    }
                                }
                                K = null;
                            }
                        }
                    }
        Console.WriteLine("Solution not found");
    }
 }
}

Voici les résultats pour les trois exemples:

Solution non trouvée

Début (1: 1) Fin (0: 0) '@': Haut, '.': Gauche, 'e': Bas, 'H': Droite

(1: 1) => (0: 1) => (0: 2) => (1: 2) => (2: 2) => (2: 1) => (2: 0) => ( 1: 0) => (0: 0)

Début (0: 0) Fin (1: 1) '0': Droite, '1': Bas, '3': Haut, '2': Gauche

(0: 0) => (1: 0) => (2: 0) => (2: 1) => (2: 2) => (1: 2) => (0: 2) => ( 0: 1) => (1: 1)

Blau
la source
Vous voudrez peut-être jouer au golf avec votre code, car il s'agit d'une compétition de golf avec code.
Timtech
Je le fais :)
Blau
D'accord, pas de précipitation :) C'est juste que certaines personnes voient un nouvel utilisateur sans code de golf et ont tendance à diminuer.
Timtech
2
C'est ma première fois ... mais je conseille que ce n'est pas encore joué au golf ... bien que je pense que je ne vais pas battre le code matemathica ... :)
Blau
Toute réponse à cette question nécessite des compétences. +1
Timtech
5

Mathematica 278

Espaces ajoutés pour "clarté"

k@l_ := (s = #~Join~-# &@{{1, 0}, {0, 1}};
         f@r_ := Flatten[MapIndexed[#2 -> #2 + (#1 /. r) &, l, {2}], 1];
         g     = Subgraph[#, t = Tuples@Range@Dimensions@l] & /@ 
                       Graph /@ f /@ (r = Thread[# -> s] & /@ Permutations[Union @@ l]);
        {t[[#]] & /@ Ordering[Tr /@ IncidenceMatrix@g[[#]]][[{1, -1}]], r[[#]]} & @@@ 
                                                                 Position[PathGraphQ /@ g, True])

Session et sortie:

 l = l1 = {{1, 2, 2, 2, 2, 1}, {1, 3, 1, 4, 1, 4}, {2, 3, 1, 3, 4, 2}, 
            {1, 4, 4, 2, 1, 3}, {2, 2, 2, 3, 2, 3}}; ;
 k@l1
 {{{{1, 1}, {3, 6}}, 
    {1 -> {1, 0}, 2 -> {0, 1}, 3 -> {-1, 0},  4 -> {0, -1}}}}

Quels sont le sommet de début, le sommet de fin et les règles de transition associées à chaque symbole.

Voici le code complémentaire pour montrer le graphe orienté:

sol = sg[[Position[PathGraphQ /@ sg, True][[1, 1]]]];
Framed@Graph[
  VertexList@sol,
  EdgeList@sol,
  VertexCoordinates -> VertexList@sol /. {x_, y_} :> {y, -x},
  VertexLabels -> MapThread[Rule, {VertexList@sol, Flatten@l}], 
  EdgeShapeFunction -> GraphElementData["FilledArcArrow", "ArrowSize" -> 0.03],
  ImagePadding -> 20]

Graphiques Mathematica

Dr. belisarius
la source
2

Mathématiques (151)

L = {{1, 2, 2, 2, 2, 1}, {1, 3, 1, 4, 1, 4}, {2, 3, 1, 3, 4, 2}, 
   {1, 4, 4, 2, 1, 3}, {2, 2, 2, 3, 2, 3}};

PathGraphQ@#~If~Print@{TopologicalSort[#]〚{1,-2}〛,r}&@
Graph@Flatten@MapIndexed[#2->#2+(#/.r)&,L,{2}]~Do~{r,
Thread[Union@@L->#]&/@{-1,0,1}~Tuples~{4,2}}

Il renvoie les règles de point de départ, de fin et de transition. Le premier index est une ligne, le second est une colonne

{{{1,1},{3,6}},{1->{1,0},2->{0,1},3->{-1,0},4->{0,-1}}}

Notez que mon code fonctionne même avec {-1,0,1}~Tuples~{4,2}. Pour accélérer, vous pouvez utiliser à la Permutations@{{1, 0}, {0, 1}, {-1, 0}, {0, -1}}place.

ybeltukov
la source
0

APL (207)

Je ne pouvais pas le rendre plus court que Mathematica, car je ne pouvais pas raisonner en termes de TopologicalSort et autres. Les gens plus intelligents sont invités à le resserrer davantage.

Golfé:

{u←∪,t←⍵⋄q r←↑(0≠+/¨r)/⊂[2]p,⍪r←{m←,⍵[u⍳t]⋄v r←⊂[1]⊃{{(↑⍴∪⍵),⊂(↑⍵)(↑⌽⍵)}n↑{3::⍬⋄i←↑⌽⍵⋄⍵,i+i⌷m}⍣n,⍵}¨⍳n←↑⍴,t⋄↑(v=n)/r}¨p←⊂[2]{1≥⍴⍵:⊃,↓⍵⋄⊃⍪/⍵,∘∇¨⍵∘~¨⍵}d←¯1 1,¯1 1×c←¯1↑⍴t⋄⊃('←→↑↓',¨u[q⍳d]),{1+(⌊⍵÷c)(c|⍵)}¨r-1}

Non golfé:

D←{⎕ML ⎕IO←3 1
    pmat←{1≥⍴⍵:⊃,↓⍵⋄⊃⍪/⍵,∘∇¨⍵∘~¨⍵}   ⍝ utility: permutations of the given vector
    u←∪,t←⍵                    ⍝ the 4 unique symbols in t←⍵
    n←↑⍴,t                     ⍝ number of elements in t
    d←¯1 1,¯1 1×c←¯1↑⍴t        ⍝ the four ∆i (+1, -1, +cols, -cols)
    p←⊂[2]pmat d               ⍝ list of permutations of the four ∆i
    r←{                        ⍝ for each permutation ⍵∊p (=interpretation of the 4 symbols)
        m←,⍵[u⍳t]              ⍝ (ravelled) t-shaped matrix of ∆i, using interpretation ⍵
        v r←⊂[1]⊃{             ⍝ for each starting index ⍵∊⍳n
            v←n↑{              ⍝ trail of visited cells after n steps 
                3::⍬           ⍝ if index out of bounds return empty list
                i←↑⌽⍵          ⍝ take last visited index
                ⍵,i+i⌷m        ⍝ follow the directions and add it to the list
            }⍣n,⍵
            (↑⍴∪v),⊂(↑v),↑⌽v   ⍝ number of unique cells, plus start/end indices
        }¨⍳n
        ↑(v=n)/r               ⍝ 1st couple of start/end indices to visit all cells (if any)
    }¨p
    q r←↑(0≠+/¨r)/⊂[2]p,⍪r     ⍝ select first perm. and start/end indices to visit all cells
    ⊃('←→↑↓',¨u[q⍳d]),{1+(⌊⍵÷c)(c|⍵)}¨r-1   ⍝ return char mapping and start/end indices
}

Exemples:

(Les indices commencent à 1)

     D⊃'122221' '131414' '231342' '144213' '222323'
 ←  4 
 →  2 
 ↑  3 
 ↓  1 
 1  1 
 3  6 
     D⊃'@..' 'e.@' 'HH@'
 ←  . 
 →  H 
 ↑  @ 
 ↓  e 
 2  2 
 1  1 
     D⊃'XXV' 'ICV' 'XIV' 'VCC' 'XXX'
 ←  C 
 →  X 
 ↑  I 
 ↓  V 
 3  1 
 5  3 
Tobia
la source