狼和鸡


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
希望能找到鸡肉
罗伯特·弗雷泽

Answers:


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 23 34 4和更高的无解)。但这将是一个无聊的程序。

说明

字段的当前状态存储为单个字符串,包括:

  • w 用小船在岸上找狼
  • c 用船在岸上吃鸡
  • \x88(位反转w)在另一岸寻找狼
  • \x9c(位相反c)在另一岸的一只鸡
  • 一个字符,指示船在P右岸的一侧,\xafP左反转)(起始侧)
  • 换行符 \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只动物。这些是cw字符。(另一侧的动物不匹配\w/(\w?)(.*)(c|w)(.+)\n(?{code})^/。然后在\n除为船选择的动物以外的其他动物之前,先将整个琴弦反转push@F,$1.$3.~"$`$2$4\xf5"。通过大写将所选动物添加到移动中:uc"$'$1$3\n"

动物选择过程可以通过许多方式有效地洗净代表它们的弦部分。因此,例如wcwcwwcc都可以代表2只狼和2只鸡。状态检查$a{$`x/\n/}++将不必要地区分这两个状态,因此将产生和检查的状态数量过多。因此,一旦不同动物的数量变多,该程序将耗尽内存和时间。一旦找到解决方案,当前版本将停止添加新状态,这一点仅得到缓解


除非我误会了你的意思4 4和更高的均数确实有解决方案,即(4,4)= WC,C,WC,W,WC,W,WW,W,WC,W,WW,W,WC

@Phaeze:在右岸WC,C,WC有两只狼和一只鸡。游戏结束
Ton Hospel '16

是的,我不好,我误解了问题的一部分。

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.。所以我认为这不是一个有效的解决方案
Ton Hospel

@Arnauld OP回答什么?我认为很明显,您只能输出最短的解决方案,而不是其他解决方案。
暴民埃里克(Erik the Outgolfer)

@Arnauld Ton Hospel是正确的。
0WJYxW9FMN

@Arnauld如果这样做,则不会打印出其他解决方案-只是最短的解决方案,那么应该没问题。
0WJYxW9FMN16年

@ J843136028希望这次我做对了。^^
Arnauld

2

果酱,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“”“]),但它们是相同的打印时)。记忆状态以[[W1 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(交叉)元运算符-有点惊讶,但它确实起作用了。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>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.