Lobos e galinhas

16

Há um rio e há lobos e galinhas de um lado do rio. Eles têm uma balsa e todos precisam chegar ao outro lado. No entanto, a balsa não pode viajar por conta própria. A jangada afundará se houver mais de dois animais. Nenhum dos animais quer se molhar porque o rio está frio e sujo. Nenhum dos animais pode pular ou voar sobre o rio. Além disso, se houver galinhas de um lado, não poderá haver mais lobos naquele lado do que galinhas desse lado - os lobos decidirão comer as galinhas. Isso significa que você não pode levar dois lobos na balsa para um lado com uma galinha.

Sua tarefa é criar um programa / função que leve um número de lobos e um número de galinhas (maior ou igual ao número de lobos) como entrada e encontre o menor número de vezes que a jangada precisa se mover através do rio. Se a tarefa não for possível, o programa / função deve gerar / retornar uma string vazia. Em seguida, ele imprimirá / retornará um método de como isso é feito da seguinte maneira:

W if a wolf crosses the river on its own
C if a chicken crosses the river on its own
CW if a chicken and a wolf cross the river -- WC is also fine
CC if two chickens cross the river
WW if two wolves cross the river

Como você pode deduzir, a balsa se moverá automaticamente em direções alternadas (esquerda e direita, começando da esquerda para a direita quando o primeiro ou dois animais cruzarem o rio). Isso não precisa ser gerado / retornado. 'W', 'C', 'CW', 'CC' ou 'WW' na saída podem ser separados por pelo menos um dos seguintes:

spaces (' ')
commas (',')
newlines

Como alternativa, você pode armazenar as instruções como itens em uma lista (uma lista vazia significa que não há solução).

Casos de teste (saída separada por vírgulas - a entrada assume o formato wolves,chickens):

1,1 -> CW

2,2 -> CW,C,CC,C,CW

1,2 -> CW,W,CW

0,10 -> CC,C,CC,C,CC,C,CC,C,CC,C,CC,C,CC,C,CC,C,CC

3,2 -> no solution

Tente tornar seu código o mais curto possível em bytes.

0WJYxW9FMN
fonte
A solução para (3,2)?
Magic Octopus Urn
@carusocomputing Não funciona, porque há mais lobos do que galinhas. Portanto, não há solução.
0WJYxW9FMN
Ahh ... Talvez rotule as entradas como W = 3, C = 2 ou algo assim; foi um pouco confuso para processar, além de que isso parece legal.
Urna Mágica do Polvo
@carusocomputing gostaria, mas acho que seria mais confuso porque a entrada é 3,2 e não W = 3, C = 2.
0JJxW9FMN
1
Esperando por uma solução em frango
Robert Fraser

Respostas:

6

Perl, 179 165 164 163 157 156 bytes

Inclui +4 para -p

Dê lobos seguidos por galinhas em STDIN

river.pl <<< "2 3"

Emite o conteúdo do barco por linha. Para este exemplo, ele fornece:

WC
C
CC
C
CC
W
WW

river.pl:

#!/usr/bin/perl -p
/ /;@F=w x$`.c x$'."\xaf\n";$a{$`x/\n/}++||grep(y/c//<y/w//&/c/,$_,~$_)or$\||=$' x/^\w*\n|(\w?)(.*)(c|w)(.+)\n(?{push@F,$1.$3.~"$`$2$4\xf5".uc"$'$1$3\n"})^/ for@F}{

Funciona como mostrado, mas substitua \xhhe \npor suas versões literais para obter a pontuação reivindicada.

Isso provavelmente será derrotado por um programa que resolve o caso geral (C> W> 0)

* output `WC W WC C` until there is only one wolf left on the left bank (--w, --c)
* output `CC C` until there is only one chicken left on the left bank (--c)
* output `WC`

Acrescente a isso as soluções triviais para apenas lobos e apenas galinhas e um caso especial codificado para 2 2e 3 3( 4 4e superior não tem solução). Mas isso seria um programa chato.

Explicação

O estado atual do campo é armazenado como uma única sequência que consiste em:

  • w para um lobo na margem com o barco
  • c para uma galinha na margem com o barco
  • \x88(pouco invertido w) para um lobo na outra margem
  • \x9c(pouco invertido c) para uma galinha na outra margem
  • Um caractere indicando o lado em que o barco está na Pmargem direita, \xaf(pouco invertido P) na margem esquerda (lado inicial)
  • uma nova linha \n
  • todos os movimentos que foram feitos até agora terminada com novas linhas, por exemplo, algo como WC\nW\nWC\nC\n(note o Ws e Cestão em maiúsculas aqui)

A matriz @Fconterá todos os estados alcançáveis. É inicializado pela string inicialwolves times "w", chickens times "c", \xaf \n

O programa faz um loop sobre o @Fqual será estendido durante o loop para que novos estados sejam processados ​​também. Para cada elemento, ele faz:

  • Observe a parte esquerda do primeiro, \nque representa a posição atual dos animais e do barco. Se isso já foi visto antes, pule$a{$`x/\n/}++
  • Verifique se há galinhas junto com mais lobos de qualquer lado. Pule se simgrep(y/c//<y/w//&/c/,$_,~$_)
  • Verifique se o barco está do outro lado, junto com todos os animais. Nesse caso, temos uma solução. Armazene $\e guarde isso, pois a primeira solução encontrada é a mais curta$\||=$' x/^\w*\n/
  • Caso contrário, tente todas as maneiras de selecionar 1 ou 2 animais ao lado do barco. Estes são os caracteres ce w. (Os animais do outro lado não combinam \w) /(\w?)(.*)(c|w)(.+)\n(?{code})^/. Em seguida, inverta a cadeia inteira antes dos, \nexceto os animais que foram selecionados para o barco push@F,$1.$3.~"$`$2$4\xf5". Adicione os animais selecionados aos movimentos, colocando-os em maiúsculas:uc"$'$1$3\n"

O processo de seleção de animais embaralha efetivamente a parte da corda que os representa de várias maneiras. Então, por exemplo, wcwce wwccambos podem representar 2 lobos e 2 galinhas. A verificação do estado $a{$`x/\n/}++distingue unicamente esses dois, pois mais estados do que o necessário serão gerados e verificados. Portanto, o programa ficará sem memória e tempo assim que o número de animais diferentes aumentar. Isso é atenuado apenas um pouco pelo fato de que a versão atual deixará de adicionar novos estados assim que uma solução for encontrada

Ton Hospel
fonte
a menos que eu entenda mal o que você está dizendo 4 4 e contagens iguais maiores têm soluções, ou seja, (4,4) = WC, C, WC, W, WC, W, WW, W, WC, W, WW, W, WC
JustinM - Restabelece Monica
@Phaeze: Depois WC,C,WCexistem 2 lobos e 1 frango na margem direita.
Fim do
Sim, meu mal, eu não entendi parte do problema.
JustinM - Restabelece Monica
5

JavaScript (ES6), 251 264 ... 244 240 bytes

Pega o número de lobos e galinhas (w, c)e retorna uma das soluções ideais, ou undefinedse não houver solução.

(w,c,v={},B=1/0,S)=>(r=(s,w,c,W=0,C=0,d=1,N=0,k=w+'|'+c+d)=>v[k]|c*w>c*c|C*W>C*C|w<0|c<0|W<0|C<0?0:w|c?[v[k]=1,2,4,8,5].map(n=>r(s+'C'.repeat(b=n>>2)+'W'.repeat(a=n&3)+' ',w-d*a,c-d*b,W+d*a,C+d*b,-d,N+1))&(v[k]=0):N<B&&(B=N,S=s))('',w,c)||S

Formatado e comentado

Função Wrapper:

(                                    // given:
  w,                                 // - w : # of wolves
  c,                                 // - c : # of chickens
  v = {},                            // - v : object keeping track of visited nodes
  B = 1 / 0,                         // - B : length of best solution
  S                                  // - S : best solution
) => (                               //
r = (...) => ...                     // process recursive calls (see below)
)('', w, c) || S                     // return the best solution

Função recursiva principal:

r = (                                // given:
  s,                                 // - s : current solution (as text)
  w, c,                              // - w/c : # of chickens/wolves on the left side
  W = 0, C = 0,                      // - W/C : # of chickens/wolves on the right side
  d = 1,                             // - d : direction (1:left to right, -1:right to left)
  N = 0,                             // - N : length of current solution
  k = w + '|' + c + d                // - k : key identifying the current node
) =>                                 //
v[k] |                               // abort if this node was already visited
c * w > c * c | C * W > C * C |      // or there are more wolves than chickens somewhere
w < 0 | c < 0 | W < 0 | C < 0 ?      // or we have created antimatter animals 
  0                                  //
:                                    // else:
  w | c ?                            //   if there are still animals on the left side:
    [v[k] = 1, 2, 4, 8, 5].map(n =>  //     set node as visited and do a recursive call
      r(                             //     for each combination: W, WW, C, CC and CW
        s + 'C'.repeat(b = n >> 2) + //     append used combination to current solution
        'W'.repeat(a = n & 3) + ' ', //     wolves = bits 0-1 of n / chickens = bits 2-3
        w - d * a,                   //     update wolves on the left side
        c - d * b,                   //     update chickens on the left side
        W + d * a,                   //     update wolves on the right side
        C + d * b,                   //     update chickens on the right side
        -d,                          //     use opposite direction for the next turn
        N + 1                        //     increment length of current solution
      )                              //
    ) &                              //     once we're done,
    (v[k] = 0)                       //     set this node back to 'not visited'
  :                                  //   else:
    N < B &&                         //     save this solution if it's shorter than the
    (B = N, S = s)                   //     best solution encountered so far

Casos de teste

Arnauld
fonte
O desafio diz and finds the smallest number of times the raft has to move across the river.. então eu não acho que esta é uma solução válida
Ton Hospel
@Arnauld O OP para responder o que ? Eu acho que está claro que você deve apenas produzir a solução mais curta, não outras.
Erik the Outgolfer
@Arnauld Ton Hospel está certo.
0JJxW9FMN
@ Arnauld Se você fizer isso para que não imprima outras soluções - apenas a solução mais curta, deve ficar bem.
0JJxW9FMN
@ J843136028 Espero que tenha acertado desta vez. ^^
Arnauld 21/10
2

CJam, 133

q~[0_]]_0+a:A;a{{28e3Zb2/{[YT2*(f*_Wf*]X..+:Bs'-&B2<{~_@<*},+{B2<T!+a:CA&{AC+:A;BY"WC".*a+}|}|}fY}fX]T!:T;__!\{0=:+!},e|:R!}g;R0=2>S*

Experimente online

Explicação:

Basicamente, o programa faz um BFS e se lembra de todos os estados que alcançou para evitar ciclos infinitos. Os estados de trabalho são representados como [[Wl Cl] [Wr Cr] M1 M2… Mn] onde W = lobos, C = galinhas, l = lado esquerdo, r = lado direito, M = movimentos feitos até agora (inicialmente nenhum), e os movimentos são como "C", "WC" ou "WW" etc. (praticamente mais como ["" C "], [" W "" C "], [" WW "" "], mas é o mesmo ao imprimir). Os estados lembrados são representados como [[Wl Cl] [Wr Cr] S] onde S é o lado do barco (0 = esquerda, 1 = direita).

q~                 read and evaluate the input ([Wl Cl] array)
[0_]               push [0 0] as the initial [Wr Cr] array
]_                 wrap both in an array (initial working state) and duplicate it
0+a                append 0 (representing left side) and wrap in an array
:A;                store in A and pop; this is the array of remembered states
a                  wrap the working state in an array
{…}g               do … while
  {…}fX            for each working state X
    28e3Zb2/       convert 28000 to base 3 and group the digits into pairs
                    this generates [[1 1] [0 2] [1 0] [2 0] [0 1]]
                    which are all possible moves represented as [Wb Cb] (b=boat)
    {…}fY          for each "numeric move" pair Y
      […]          make an array of…
        YT2*(f*    Y negated if T=0 (T is the current boat side, initially 0)
        _Wf*       and the (arithmetic) negation of the previous pair
      X..+         add the 2 pairs to X, element by element
                    this performs the move by adding & subtracting the numbers
                    from the appropriate sides, determined by T
      :Bs          store the updated state in B, then convert to string
      '-&          intersect with "-" to see if there was any negative number
      B2<          also get just the animal counts from B (first 2 pairs)
      {…},         filter the 2 sides by checking…
        ~_@<*      if W>C>0 (it calculates (C<W)*C)
      +            concatenate the results from the negative test and eating test
      {…}|         if it comes up empty (valid state)…
        B2<        get the animal counts from B (first 2 pairs)
        T!+        append !T (opposite side)
        a:C        wrap in an array and store in C
        A&         intersect with A to see if we already reached that state
        {…}|       if not, then…
          AC+:A;   append C to A
          BY       push B and Y (updated state and numeric move)
          "WC".*   repeat "W" and "C" the corresponding numbers of times from Y
                    to generate the alphabetic move
          a+       wrap in array and append to B (adding the current move)
  ]                collect all the derived states in an array
  T!:T;            reverse the side with the boat
  __!              make 2 copies of the state array, and check if it's empty
  \{…},            filter another copy of it, checking for each state…
    0=:+!          if the left side adds up to 0
  e|:R             logical "or" the two and store the result in R
  !                (logically) negate R, using it as a do-while condition
                    the loop ends when there are no more working states
                    or there are states with the left side empty
;                  after the loop, pop the last state array
R0=2>S*            if the problem is solved, R has solution states,
                    and this extracts the moves from the first state
                    and joins them with space
                   if there's no solution, R=1
                    and this repeats a space 0 times, resulting in empty string
aditsu
fonte
0

Perl 6 , 268 bytes

->*@a {(
[X](0 X..@a)[1..*-2]
.grep({![>](|$_,0)&![>](|(@a Z-$_),0)})
.combinations(2)
.combinations
.map(|*.permutations)
.map({.map(|*)»[*]})
.map({((|$_,(0,0)ZZ-@a,|$_)ZX*|(-1,1)xx*)»[*]})
.grep({.all.&{.all>=0&&3>.sum>0}})
.map({.map:{[~](<W C>Zx$_)}})
if [<=] @a
)[0]//()}

Gera cadeias de (wolf count, chicken count)estados cada vez mais longas para a margem esquerda e retorna o primeiro que corresponde a todas as regras.

Acontece que essa abordagem não é eficiente nem muito concisa, mas pelo menos foi divertido escrever.
Eu não acho que eu nunca empilhados do Z(zip) e X(cruz) meta-operadores antes, como o ZZ-e ZX*aqui - surpreendeu meio que realmente funcionou.

(As novas linhas são adicionadas apenas para fins de exibição e não fazem parte da contagem de bytes.)

smls
fonte
0

JavaScript (ES6), 227237

Basicamente, ele faz um BFS e se lembra de todos os estados que alcançou para evitar ciclos infinitos. Ao contrário do @ aditsu, não acho que haja espaço para jogar golfe

v=>g=>eval("o=[],s=[[v,g,0,k=[]]];for(i=0;y=s[i++];k[y]=k[y]||['WW','C','CC','W','CW'].map((u,j)=>(r=w-(j?j/3|0:2),q=c-j%3,d=g-q,e=v-r,r<0|q<0|!!q&r>q|!!d&e>d)||s.push([e,d,!z,[...p,u]])))o=([w,c,z,p]=y,y[3]=!z|c-g|w-v)?o:i=p")

Menos golfe

(v,g) => {
  o = []; // output
  k = []; // hashtable to check states already seen
  s=[[v, g, 0, []]]; // states list: each element is wolves,chickens,side,path
  for(i = 0; 
      y = s[i++]; // exit loop when there are no more states to expand
     )
  {
    [w, c, z, p] = x; // wolves on this side, chickens on this side, side, path
    if (z && c==g && w==v) // if all chicken and wolves on the other side
      o = p, // the current path is the output
      i = p  // this will force the loop to terminate
    y[3] = 0; // forget the path, now I can use y as the key to check state and avoid cycles
    if (! k[y]) // it's a new state
    {
       k[y] = 1; // remember it
       ['WW','C','CC','W','CW'].map( (u,j)=> (
          a = j ? j/3|0 : 2, // wolves to move
          b = j % 3, // chicken to move  
          r = w - a, // new number of wolves on this side 
          q = c - b, // new number of chickens on this side
          e = v - r, // new number of wolves on other side
          d = g - q, // new number of chickens on other side
          // check condition about the number of animals together
          // if ok, push a new state
          r<0 |q<0 | !!q&r>q | !!d&e>d || 
            s.push([e, d, !z, [...p,u]) 
       )
    }
  }
  return o
}

Teste

F=
v=>g=>eval("o=[],s=[[v,g,0,k=[]]];for(i=0;y=s[i++];k[y]=k[y]||['WW','C','CC','W','CW'].map((u,j)=>(r=w-(j?j/3|0:2),q=c-j%3,d=g-q,e=v-r,r<0|q<0|!!q&r>q|!!d&e>d)||s.push([e,d,!z,[...p,u]])))o=([w,c,z,p]=y,y[3]=!z|c-g|w-v)?o:i=p")

function update() {
  var c=+C.value, w=+W.value
  O.textContent=F(w)(c)
}

update()
input { width: 4em }
Chickens <input id=C value=2 type=number min=0 oninput='update()'>
Wolves <input id=W value=2 type=number min=0 oninput='update()'>
<pre id=O></pre>

edc65
fonte