Determine qué valor representa qué dirección en una ruta

10

Edición importante: Anteriormente, había un valor incorrecto en el Ejemplo 1. Se ha solucionado.

Se le proporciona una matriz bidimensional en la que cada celda contiene uno de los cuatro valores.

Ejemplos:

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

Los cuatro valores representan flechas direccionales (arriba, abajo, izquierda y derecha), aunque no sabe qué valor representa qué dirección.

Las flechas direccionales forman una ruta ininterrumpida que incluye todas las celdas de la matriz, aunque no sabe dónde están los puntos de inicio o finalización.

Escriba un código que determine en qué dirección representa cada uno de los cuatro valores y dónde están los puntos inicial y final.

Un valor de retorno aceptable para una matriz que contiene los valores A, B, C y D sería algo así como:

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

Debido a que puede atravesar el camino en ambos sentidos (de principio a fin y de final a inicio), siempre habrá más de una solución correcta, y puede haber más de dos. Suponga que las entradas que recibe (como en los ejemplos anteriores) siempre tienen al menos una solución correcta. En los casos en que hay más de una solución correcta, devolver solo una de las soluciones correctas es suficiente.

El código más corto gana. Elegiré el ganador después de 7 días o 24 horas sin una nueva presentación, lo que ocurra primero.

Incluyo soluciones a los ejemplos anteriores, pero le animo a que las verifique solo una vez que haya escrito su código:

Uno:

{arriba: 3, abajo: 1, izquierda: 4, derecha: 2, inicio: [0,0], final: [2,5]}

Dos:

{arriba: '@', abajo: 'e', ​​izquierda: '.', derecha: 'H', inicio: [1,1], final: [0,0]}

Tres:

{arriba: 'I', abajo: 'V', izquierda: 'C', derecha: 'X', inicio: [0,2], final: [4,2]}

jawns317
fuente
1
"puede atravesar el camino en ambos sentidos": si las direcciones son absolutas, no relativas, esto no es cierto. ¿Las direcciones son absolutas o relativas? Además, ¿se sabe que el inicio y el final están fuera de la matriz?
John Dvorak
@ JanDvorak Los puntos inicial y final son celdas dentro de la matriz. En cuanto a las direcciones, suponga que siempre indican movimiento hacia una celda adyacente (norte, sur, este u oeste).
jawns317
En cuyo caso no es posible atravesar un camino hacia atrás. No veo ninguna garantía de que siempre habrá más de una solución.
John Dvorak
1
Si "asumimos que siempre indican movimiento hacia una celda adyacente", ¿su segundo ejemplo sigue siendo válido? Puede que me falte algo, pero parece que @ no podría ser ninguna de las cuatro direcciones sin ir "fuera de los límites".
Nick Sarabyn
1
El ejemplo 1 no tiene solución.
DavidC

Respuestas:

6

C#

EDITAR: se corrigió una división y formato. Y agregó la clase auxiliar.

Este es el código de golf, 807 caracteres

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;}}}
}    

Resultados para los tres casos de prueba:

Abajo: '1', Derecha: '2', Arriba: '3', Izquierda: '4' Inicio (0: 0) Fin (5: 2)
Arriba: '@', Izquierda: '.', Abajo: ' e ', Derecha:' H 'Inicio (1: 1) Fin (0: 0)
Derecha:' X ', Abajo:' V ', Arriba:' I ', Izquierda:' C 'Inicio (0: 2) Fin (2: 4)

Este es el código en bruto sin "golf", casi 4.000 caracteres:

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");
    }
 }
}

Estos son los resultados de los tres ejemplos:

Solución no encontrada

Inicio (1: 1) Fin (0: 0) '@': Arriba, '.': Izquierda, 'e': Abajo, 'H': Derecha

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

Inicio (0: 0) Fin (1: 1) '0': Derecha, '1': Abajo, '3': Arriba, '2': Izquierda

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

Blau
fuente
Es posible que desee golf su código, ya que esta es una competencia de código de golf.
Timtech
Lo estoy haciendo :)
Blau
De acuerdo, no hay prisa :) Es solo que algunas personas ven a un nuevo usuario sin código de golf y tienden a votar en contra.
Timtech
2
Es mi primera vez ... pero te aconsejo que todavía no se juega golf ... aunque creo que no superaré el código matemathica ... :)
Blau
Cualquier respuesta a esta pregunta requiere habilidad. +1
Timtech
5

Mathematica 278

Espacios añadidos para "claridad"

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])

Sesión y salida:

 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}}}}

Cuál es el Vertex inicial, el Vertex final y las reglas de transición asociadas con cada símbolo.

Aquí está el código complementario para mostrar el gráfico orientado:

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]

Gráficos de Mathematica

Dr. belisario
fuente
2

Mathematica (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}}

Devuelve el punto de inicio, el punto final y las reglas de transición. El primer índice es fila, el segundo es columna

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

Tenga en cuenta que mi código funciona incluso con {-1,0,1}~Tuples~{4,2}. Para acelerar puede usar Permutations@{{1, 0}, {0, 1}, {-1, 0}, {0, -1}}en su lugar.

ybeltukov
fuente
0

APL (207)

No pude hacerlo más corto que Mathematica, porque no podía razonar en términos de TopologicalSort y demás. Las personas más inteligentes pueden exprimirlo aún más.

Golfizado:

{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}

Sin 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
}

Ejemplos:

(Los índices comienzan en 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
fuente