Волки и куры


15

Там есть река, а с одной стороны реки есть волки и куры. У них есть плот, и все они должны перейти на другую сторону. Однако плот не может путешествовать сам по себе. Плот затонет, если на нем более двух животных. Никто из животных не хочет промокнуть, потому что река холодная и грязная. Ни одно из животных не может прыгать или летать через реку. Кроме того, если на одной стороне есть цыплята, на этой стороне не может быть больше волков, чем на той стороне - волки решат съесть цыплят. Это означает, что вы не можете взять двух волков на плоту в сторону с одной курицей.

Ваша задача состоит в том, чтобы создать программу / функцию, которая принимает в качестве входных данных количество волков и кур (больше или равно количеству волков) и находит наименьшее число раз, когда плоту приходится перемещаться по реке. Если задача невозможна, программа / функция должна вывести / вернуть пустую строку. Затем он напечатает / вернет один метод, описывающий, как это делается следующим образом:

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

Как вы можете сделать вывод, плот автоматически будет двигаться в чередующихся направлениях (влево и вправо, начиная слева направо, когда первые одно или два животных пересекают реку). Это не нужно выводить / возвращать. «W», «C», «CW», «CC» или «WW» в выходных данных могут быть разделены хотя бы одним из следующих элементов:

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

Кроме того, вы можете сохранить направления как элементы в списке (пустой список означает отсутствие решения).

Тестовые случаи (выходные данные разделены запятыми - ввод принимает форму 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

Попробуйте сделать свой код максимально коротким в байтах.


Решение для (3,2)?
Волшебная Урна Осьминога

@carusocomputing Это не работает, потому что волков больше, чем цыплят. Так что нет решения.
0WJYxW9FMN

Ааа ... Может быть, пометить входы как W = 3, C = 2 или что-то; было немного запутанно, но это выглядит круто.
Волшебная Урна Осьминога

@carusocomputing Я бы хотел, но я думаю, что это было бы более запутанным, потому что ввод 3,2, а не W = 3, C = 2.
0WJYxW9FMN

1
Надеясь на решение в курице
Роберт Фрейзер

Ответы:


5

Perl, 179 165 164 163 157 156 байт

Включает +4 для -p

Отдайте волков с последующими цыплятами на STDIN

river.pl <<< "2 3"

Выводит содержимое лодки на строку. Для этого примера это дает:

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

Работает, как показано, но заменить \xhh и \nих буквальными версиями, чтобы получить заявленную оценку.

Это, вероятно, будет побеждено программой, которая решает общий случай (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`

Добавьте к этому тривиальные решения только для волков и только цыплят, а также в специальном жестком кейсе для 2 2 и 3 3( 4 4и выше не имеют решения). Но это была бы скучная программа.

объяснение

Текущее состояние поля хранится в виде одной строки, состоящей из:

  • w для волка на берегу с лодкой
  • c за курицу на берегу с лодкой
  • \x88 (немного перевернутый w ) для волка на другом берегу
  • \x9c (немного перевернутый c ) для курицы на другом берегу
  • Символ, обозначающий сторону, на которой находится лодка, Pдля правого берега \xaf(бит перевернутP ) для левого берега (начальная сторона)
  • новая строка \n
  • все ходы, которые были сделаны до сих пор, заканчиваются символами новой строки, например что-то вроде WC\nW\nWC\nC\n(обратите внимание на Ws и Cздесь в верхнем регистре)

Массив @Fбудет содержать все достижимые состояния. Инициализируется начальной строкойwolves times "w", chickens times "c", \xaf \n

Затем программа зацикливается, @Fчто расширяется во время зацикливания, так что обрабатываются и новые состояния. Для каждого элемента он делает:

  • Посмотрите на часть строки слева от первой, \nкоторая представляет текущее положение животных и лодки. Если это было замечено до пропуска$a{$`x/\n/}++
  • Проверьте, есть ли цыплята вместе с большим количеством волков с любой стороны. Пропустить если такgrep(y/c//<y/w//&/c/,$_,~$_)
  • Проверьте, находится ли лодка на дальней стороне вместе со всеми животными. Если так, у нас есть решение. Сохраните это $\и сохраните, так как первое найденное решение является самым коротким$\||=$' x/^\w*\n/
  • В противном случае попробуйте все способы выбора 1 или 2 животных на стороне с лодкой. Это cи wсимволы. (Животные на другой стороне не будут совпадать \w) /(\w?)(.*)(c|w)(.+)\n(?{code})^/. Затем немного переверните всю строку перед \nисключением животных, которые были выбраны для лодки push@F,$1.$3.~"$`$2$4\xf5". Добавьте выбранных животных в ходы, поместив их в верхний регистр:uc"$'$1$3\n"

Процесс отбора животных эффективно перетасовывает представляющую их часть строки разными способами. Так, например, wcwcи wwccмогут представлять 2 волка и 2 куры. Проверка состояния $a{$`x/\n/}++будет необоснованно различать эти два, поэтому будет создано и проверено гораздо больше состояний, чем необходимо. Поэтому программе не хватит памяти и времени, как только количество разных животных увеличится. Это немного смягчается тем фактом, что текущая версия перестанет добавлять новые состояния, когда будет найдено решение


если я не пойму, что вы говорите, 4 и более равные числа имеют решения, то есть (4,4) = WC, C, WC, W, WC, W, WW, W, WC, W, WW, W, WC

@Phaeze: После WC,C,WCтого, как на правом берегу есть 2 волка и 1 курица. Игра окончена
Тон Хоспел

Да, мой плохой, я неправильно понял часть проблемы.

4

JavaScript (ES6), 251 264 ... 244 240 байт

Принимает количество волков и кур (w, c)и возвращает одно из оптимальных решений, или, undefinedесли решения не существует.

(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

Отформатировано и прокомментировано

Функция обертки:

(                                    // 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

Основная рекурсивная функция:

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

Контрольные примеры


Задача говорит and finds the smallest number of times the raft has to move across the river.. так что я не думаю, что это правильное решение
Тон Хоспел

@Arnauld ОП ответить на то , что ? Я думаю, ясно, что вы должны выводить только самое короткое решение, а не другие.
Эрик Outgolfer

@ Arnauld Ton Hospel прав.
0WJYxW9FMN

@Arnauld Если вы сделаете так, чтобы он не распечатывал другие решения - только самое короткое решение, тогда все должно быть хорошо.
0WJYxW9FMN

@ J843136028 Надеюсь, на этот раз я все понял правильно. ^^
Арно

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*

Попробуйте онлайн

Объяснение:

По сути, программа выполняет BFS и запоминает каждое состояние, которого достигла, чтобы избежать бесконечных циклов. Рабочие состояния представлены как [[Wl Cl] [Wr Cr] M1 M2… Mn], где W = волки, C = цыплята, l = левая сторона, r = правая сторона, M = ходы, сделанные до сих пор (изначально ни одного), и ходы похожи на "C", "WC" или "WW" и т. д. (практически больше похоже на ["" "C"], ["W" "C"], ["WW" ""]), но это то же самое при печати). Запомненные состояния представлены как [[Wl Cl] [Wr Cr] S], где S - сторона с лодкой (0 = слева, 1 = справа).

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

0

Perl 6 , 268 байт

->*@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]//()}

Создает все более длинные цепочки (wolf count, chicken count)состояний для левого берега и возвращает первое, соответствующее всем правилам.

Оказывается, этот подход не является ни эффективным, ни очень кратким, но по крайней мере было весело писать.
Я не думаю, что я никогда раньше не складывал Z(zip) и X(cross) мета-операторы, как ZZ-и ZX*здесь - немного удивлен, что это действительно сработало.

(Символы новой строки просто добавляются для отображения и не являются частью количества байтов.)


0

JavaScript (ES6), 227 237

По сути, он выполняет BFS и запоминает каждое состояние, которого достиг, чтобы избежать бесконечных циклов. В отличие от @ aditsu, я не думаю, что есть место для игры в гольф

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

Меньше гольфа

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

Тестовое задание

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>

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.