オオカミと鶏


16

川があり、川の片側にはオオカミと鶏がいます。彼らはいかだを持っており、彼らはすべて反対側に到達する必要があります。ただし、いかだは単独では移動できません。3匹以上の動物が乗っていると、いかだは沈みます。川は寒くて汚いので、動物は誰も濡れません。どの動物も川を飛び越えたり、飛ぶことはできません。また、片側に鶏がいる場合、その側に鶏がいるよりも多くのオオカミがいることはできません-その後、オオカミは鶏を食べることにします。つまり、いかだに乗った2匹のオオカミを1羽の鶏と一緒に横に連れて行くことはできません。

あなたのタスクは、入力としてオオカミの数とニワトリの数(オオカミの数以上)を受け取り、いかだが川を横切る必要がある最小回数を見つけるプログラム/関数を作成することです。タスクが不可能な場合、プログラム/関数は空の文字列を出力/返す必要があります。次に、これが次のように行われる方法に関する1つのメソッドを出力/返します。

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

推測できるように、ラフトは自動的に交互の方向に移動します(最初の1頭または2頭の動物が川を渡るときに左から右に向かって)。これを出力/返す必要はありません。出力の「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)の解決策は?
魔法のタコUr

@carusocomputingニワトリよりもオオカミの数が多いため、機能しません。したがって、解決策はありません。
0WJYxW9FMN

Ahh ...入力にW = 3、C = 2などのラベルを付けます。これはクールに見えることを除いて、処理するのが少し混乱しました。
魔法のタコUr

@carusocomputing私はそうしますが、入力はW = 3、C = 2ではなく3,2であるため、より混乱すると思います。
0WJYxW9FMN

回答:


6

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右岸にある側を示す文字\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/,$_,~$_)
  • ボートがすべての動物と一緒に向こう側にあるかどうかを確認します。その場合、解決策があります。その店$\と最初のソリューションFOUNDが最短であるため、という続けます$\||=$' x/^\w*\n/
  • それ以外の場合は、ボートの横にある1匹または2匹の動物を選択するすべての方法を試してください。これらはcw文字です。(反対側の動物は一致しません\w/(\w?)(.*)(c|w)(.+)\n(?{code})^/。それから\nボートのために選ばれた動物を除く前のひも全体を少し逆にしますpush@F,$1.$3.~"$`$2$4\xf5"。選択した動物を大文字で移動して追加します。uc"$'$1$3\n"

動物選択プロセスは、それらを表す文字列部分をさまざまな方法で効果的にシャッフルします。たとえばwcwcwwcc2匹のオオカミと2羽の鶏を表すことができます。状態チェック$a{$`x/\n/}++はこれら2つの状態を不当に区別するため、必要以上に多くの状態が生成され、チェックされます。したがって、異なる動物の数が増えるとすぐに、プログラムはメモリと時間を使い果たします。これは、解決策が見つかると現在のバージョンが新しい状態の追加を停止するという事実によって少しだけ緩和されます


あなたが言っていることを誤解しない限り、4 4以上の等しいカウントには解決策があります。つまり、(4,4)= WC、C、WC、W、WC、W、WW、W、WC、W、WW、W、WC
JustinM -復活モニカ

@Phaeze:WC,C,WC右岸に2匹のオオカミと1 羽の鶏がいます。ゲームオーバー
トンホスペル

ええ、私は問題の一部を誤解しました。
JustinM -復活モニカ

5

JavaScript(ES6)、251 264 ... 244 240バイト

オオカミとニワトリの数を取得し(w, c)、最適な解決策の1つを返します(解決策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.ます。私はないと思うので、これは有効なソリューションです
トンHospel

@Arnauld OPはに答えます?他のソリューションではなく、最短のソリューションのみを出力する必要があることは明らかだと思います。
エリックアウトゴルファー

@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)左の銀行のますます長くなる状態のチェーンを生成し、すべてのルールに一致する最初のチェーンを返します。

このアプローチは効率的でも非常に簡潔でもないことがわかりましたが、少なくとも書くのは楽しかったです。ここやのように(zip)と(cross)のメタ演算子
を一度も重ねたことがないとは思わない-実際に機能していることにちょっと驚いた。ZXZZ-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>

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.