Determinar qual valor representa qual direção em um caminho

10

Edição importante: Anteriormente, havia um valor incorreto no Exemplo 1. Foi corrigido.

Você recebe uma matriz bidimensional na qual cada célula contém um dos quatro valores.

Exemplos:

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

Os quatro valores representam setas direcionais (para cima, para baixo, esquerda e direita), embora você não saiba qual valor representa qual direção.

As setas direcionais formam um caminho ininterrupto que inclui todas as células da matriz, embora você não saiba onde estão os pontos inicial e final.

Escreva um código que determine qual direção cada um dos quatro valores representa e onde estão os pontos inicial e final.

Um valor de retorno aceitável para uma matriz que contém os valores A, B, C e D seria algo como:

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

Como você pode percorrer o caminho nos dois sentidos (do início ao fim e do fim ao início), sempre haverá mais de uma solução correta e pode haver mais de duas. Suponha que as entradas que você recebe (como nos exemplos acima) sempre tenham pelo menos uma solução correta. Nos casos em que há mais de uma solução correta, basta retornar uma das soluções corretas.

O menor código vence. Escolherei o vencedor após 7 dias ou 24 horas sem uma nova inscrição, o que ocorrer primeiro.

Estou incluindo soluções para os exemplos acima, mas recomendamos que você as verifique somente depois de escrever seu código:

1:

{para cima: 3, para baixo: 1, para a esquerda: 4, para a direita: 2, início: [0,0], final: [2,5]}

Dois:

{acima: '@', abaixo: 'e', ​​esquerda: '.', direita: 'H', início: [1,1], final: [0,0]}

Três:

{acima: 'I', abaixo: 'V', esquerda: 'C', direita: 'X', início: [0,2], final: [4,2]}

jawns317
fonte
11
"você pode percorrer o caminho nos dois sentidos" - se as direções forem absolutas, não relativas, isso não é verdade. As direções são absolutas ou relativas? Além disso, sabe-se que o início e o fim estão fora da matriz?
John Dvorak
@JanDvorak Os pontos inicial e final são células dentro da matriz. Quanto às direções, suponha que elas sempre indiquem movimento em uma célula adjacente (norte, sul, leste ou oeste).
Jawns317
Nesse caso, não é possível percorrer um caminho para trás. Não vejo nenhuma garantia de que sempre haverá mais de uma solução.
John Dvorak
11
Se "assumirmos que eles sempre indicam movimento em uma célula adjacente", seu segundo exemplo ainda é válido? Posso estar faltando alguma coisa, mas parece que @ não poderia ser uma das quatro direções sem sair "dos limites".
precisa saber é o seguinte
11
O exemplo 1 não tem solução.
DavidC

Respostas:

6

C #

EDIT: Corrigida uma divisão e formatação. E adicionou a classe auxiliar.

Este é o código do golfe, 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 os três casos de teste:

Abaixo: '1', Direita: '2', Acima: '3', Esquerda: '4' Início (0: 0) Fim (5: 2)
Acima: '@', Esquerda: '.', Abaixo: ' e ', Direita:' H 'Início (1: 1) Fim (0: 0)
Direita:' X ', Abaixo:' V ', Acima:' I ', Esquerda:' C 'Início (0: 2) Fim (2: 4)

Este é o código bruto sem "golf", com quase 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");
    }
 }
}

Estes são os resultados para os três exemplos:

Solução não encontrada

Início (1: 1) Fim (0: 0) '@': Acima, '.': Esquerda, 'e': Abaixo, 'H': Direita

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

Início (0: 0) Fim (1: 1) '0': Direita, '1': Abaixo, '3': Acima, '2': Esquerda

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

Blau
fonte
Você pode jogar seu código no golfe, pois esta é uma competição de golfe com código.
Timtech
Estou fazendo isso :)
Blau
Ok, não tem pressa :) É que algumas pessoas veem um novo usuário sem código de golfe e tendem a votar de forma negativa.
Timtech
2
É a minha primeira vez ... mas eu aconselho que ainda não está golfed ... embora eu acho que não vai bater código matemathica ... :)
Blau
Qualquer resposta a esta pergunta requer habilidade. 1
Timtech
5

Mathematica 278

Espaços adicionados para "clareza"

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

Sessão e Saída:

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

Qual é o vértice inicial, o vértice final e as regras de transição associadas a cada símbolo.

Aqui está o código complementar para mostrar o 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 do Mathematica

Dr. belisarius
fonte
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}}

Retorna o ponto inicial, o ponto final e as regras de transição. O primeiro índice é linha, o segundo é coluna

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

Observe que meu código funciona mesmo com {-1,0,1}~Tuples~{4,2}. Para acelerar, você pode usar Permutations@{{1, 0}, {0, 1}, {-1, 0}, {0, -1}}.

ybeltukov
fonte
0

APL (207)

Eu não poderia torná-lo mais curto que o Mathematica, porque não conseguia raciocinar em termos de TopologicalSort e tal. Pessoas mais inteligentes são bem-vindas para apertar ainda mais.

Golfe:

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

Ungolfed:

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
}

Exemplos:

(Os índices começam em 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
fonte