Nドア、Kモンキーズ


13

N個のドアとK個の猿がいます。最初は、すべてのドアが閉じられています。

ラウンド1:最初のサルがすべてのドアを訪れ、ドアを切り替えます(ドアが閉じている場合は開かれ、開いている場合は閉じられます)。

ラウンド2:最初のサルがすべてのドアを訪れ、ドアを切り替えます。その後、2番目のサルは2番目のドアごとに訪問し、ドアを切り替えます。

。。。

。。。

ラウンドk: 最初のサルがすべてのドアを訪れ、ドアを切り替えます。。。。。。。。。。k番目のサルはk番目のドアをすべて訪れ、ドアを切り替えます。

入力: NK(単一のスペースで区切られる)

出力: 単一のスペースで区切られた開いているドア番号。

入力:3 3

出力:1 2

制約

0 <N <101

0 <= K <= N

  • N個のドアには1からNまでの番号が付けられ、K個の猿には1からKまでの番号が付けられているとします

  • 最短のコードを持つものが勝ちます。また、N = 23、K = 21の出力を表示します


このパズルに触発された?
数学チラー

質問があります。N= Kの場合、すべての素数のドアが開いていますよね?
Fabinout

@Fabinout no n=k=3は出力する1 2ので、間違っています...そして5つの出力1 2 4にはパターンがありますが、それはそれほど明白ではありません。
数学チラー

@Fabinoutは、非常に奇妙なタイプのフィボナッチ数セット、非常に高度な抽象数学に従います。
数学チラー

@tryingToGetProgrammingStraightその通り、私の記憶は、答えは素数のリストであり、それが平方数のリストだったと言っていました。
Fabinout

回答:


14

APL、32 28 26

{(2|+/(⍳⍺)∘.{+/0=⍺|⍨⍳⍵}⍳⍵)/⍳⍺}/⎕

⎕:
      23 21
 1 2 4 8 9 16 18 23 

説明

  • {+/0=⍺|⍨⍳⍵}は、ドア(左の引数)がラウンド(右の引数)でトグルされる回数を返す関数です。これは、その因子の数と等しい≤ です。

    • ⍳⍵ 1から数値配列を生成

    • ⍺|⍨その配列の各アイテムごとにモジュラスを計算します

    • 0= 0があった1に変更し、その他すべての場合は0に変更します

    • +/ 結果の配列を合計します

  • 外部関数:

    • (⍳⍺)⍳⍵1〜N および1〜Kの配列を生成

    • ∘.{...}2つの配列の要素のペアごとに、関数を適用します。これは、トグルされた回数のマトリックスを提供し、各行はドアを表し、各列はラウンドを表します。

    • +/列を合計します。これは、各ドアがすべてのラウンドで切り替えられる回数の配列を提供します。

    • 2|モジュラス2なので、ドアが開いている場合は1です。閉じている場合は0です。

    • (...)/⍳⍺ 最後に、1〜Nの配列を生成し、前の手順で配列に1が存在する配列のみを選択します。

  • /⎕ 最後に、入力からの数字の間に関数を挿入します。


編集

{(2|+⌿0=(,↑⍳¨⍳⍵)∘.|⍳⍺)/⍳⍺}/⎕
  • ,↑⍳¨⍳⍵すべての「サル」を生成(K = 4の場合、これは1 0 0 0 1 2 0 0 1 2 3 0 1 2 3 4

    • ⍳⍵1から(K)の配列

    • ⍳¨ それらのそれぞれについて、1からその番号までの配列を生成します

    • ,↑ネストされた配列を行列に変換し()、次に単純な配列に分解します(,

  • (,↑⍳¨⍳⍵)∘.|⍳⍺1から(N)までの各番号について、各サルで変更します。

  • 0=0があった1に変更し、それ以外の場合は0に変更します。これにより、トグルのマトリックスが得られます。行は各ラウンドの各猿、列はドアです。1はトグル、0はトグルなしを意味します。

  • +⌿ 行を合計して、各ドアが切り替えられた回数の配列を取得します

他の部分は変更されません


編集

{(≠⌿0=(,↑⍳¨⍳⍵)∘.|⍳⍺)/⍳⍺}/⎕

≠⌿sumおよびmod 2(2|+⌿)の代わりにXOR reduce()を使用します


APLはゴルフスクリプト用に設計されましたか?;-)
celtschk

@celtschkはい、部分的には、ある意味で。アルゴリズムを簡潔に表現するために設計されました。
luserはドローグ

{}/NとKをdfnの引数として使用するのではなく、dfnリダクションを使用するのはなぜですか?
アダム

@Adám1)これは私の過去だからです。2)この質問は、「プログラムまたは機能」およびI / Oの標準化よりも前のものです。3)OPが「単一のスペースで区切られている」と具体的に言った
TwiNight

十分ですが、少なくとも1バイトを節約できますi←⍳⍺
アダム

4

GolfScript、33文字

~:k;),1>{0\{1$)%!k@-&^}+k,/}," "*

ドアの番号がゼロから始まる場合、3文字節約されます。

例(オンライン):

> 3 3
1 2

> 23 21
1 2 4 8 9 16 18 23

3

Mathematica、104文字

{n,k}=FromDigits/@StringSplit@InputString[];Select[Range@n,OddQ@DivisorSum[#,If[#>k,0,k+1-#]&]&]~Row~" "

例:

In [1]:= {n、k} = FromDigits / @ StringSplit @ InputString []; Select [Range @ n、OddQ @ DivisorSum [#、If [#> k、0、k + 1-#]&]& ]〜行〜 ""

?23 21

Out [1] = 1 2 4 8 9 16 18 23


1
入力ストリームを想定して、入力の解析からさらに15文字をノックできます{n,k}=%~Read~{Number,Number}。例:。
マルクストーマス

3

ルビー、88

@manatworkの回答に基づきます。

gets;~/ /
$><<(1..$`.to_i).select{|d|(1..k=$'.to_i).count{|m|d%m<1&&(k-m+1)%2>0}%2>0}*$&

これらの危険なグローバルは常に構文の強調表示を壊します!


申し訳ありませんが、90文字(リビジョン2)と86文字(リビジョン3)はバグがあるようです。新しい数字22が結果に表示されました。
マナトワーク

@manatworkいいですね、2文字のコストで修正したと思います。私はそのcountビットをさらに改善できると感じています、ルビーに#sumそのようなことのための組み込みメソッドがあればいいのにと思います:>
ポール・プレスティッジ

うわー!本当に感動しました。
マナトワーク

3

Python 3、 97 84

猿が偶数回のラウンドで出現した場合、それはまったく変化しません。猿が偶数回出現する場合、それは正確に1ラウンドと同じです。

したがって、一部のサルは除外される可能性があり、他のサルはドアを一度切り替えるだけです。

N,K=map(int,input().split())
r=set()
while K>0:r^=set(range(K,N+1,K));K-=2
print(*r)

の出力23 21

1 2 4 8 9 16 18 23

集合演算の賢い使用!私はあなたが短くなることができると思いますrange(2-K%2,K+1,2)range(K,0,-2)
xnor 14年

または、forループをループに置き換えてwhileください:while K>0:r^=set(range(K,N+1,K));K-=2
xnor

@xnor:ありがとう、それは素晴らしい!
モニカを復元する14

2

R-74

x=scan(n=2);cat(which(colSums((!sapply(1:x[1],`%%`,1:x[2]))*x[2]:1)%%2>0))

シミュレーション:

> x=scan(n=2);cat(which(colSums((!sapply(1:x[1],`%%`,1:x[2]))*x[2]:1)%%2>0))
1: 23 21
Read 2 items
1 2 4 8 9 16 18 23

2

javascript 148 127

function e(n,k){b=array(n);d=[];function a(c){for(i=0;i<n;i+=c)b[i]=!b[i];c<k&&a(c+1)}a(1);for(i in b)b[i]&&d.push(i);return d}

ここに(小さな)読み取り可能なバージョンがあります:

function e(n, k) {     //define N and K
     b = array(n); //declare all doors as closed
     d = [];     //create array later used to print results

     function a(c) {   //(recursive) function that does all the work
         for (i = 0; i < n; i += c)  //increment by c until you reach N and...
              b[i] = !b[i];  //toggle said doors
         c < k && a(c + 1)  //until you reach k, repeat with a new C (next monkey)
     }
     a(1); //start up A

     for (i in b) b[i] && d.push(i); //convert doors to a list of numbers
     return d //NO, i refuse to explain this....
}   //closes function to avoid annoying errors

デモフィドル

0からカウントを開始することに注意する必要があります(技術的にはオフバイワンエラー)


2行目を変更すると、3行目を削除できます。b=Array(n);これにより、未定義の長さnで配列が初期化されます。!undefinedはtrueであるため、最初のモンキーパスですべてがtrueになります。
path411

@ path411ありがとうございます!「適切な」配列宣言がどのように機能するか忘れてしまったことに驚きました。気軽に+1
Math chiller 2013年

面白い。N = 23、K = 21の場合と同様の答えが得られるように見えるのは、これまで見てきた唯一のものです。唯一の違いは、0を含み23を除外するoff-by-oneの問題です。
Iszi13年

私の何が問題なのかを突き止めましたが、これには同じ問題があります。ラウンドごとに、すべてのドアから1匹の猿だけを送ります。ただし、チャレンジの仕様に従って、各ラウンドを$ iのサルが走っている必要があります-$ iはあなたが参加しているラウンドの番号です。
イッツィ

2

JavaScript、153

(function(g){o=[],f=g[0];for(;i<g[1];i++)for(n=0;n<=i;n++)for(_=n;_<f;_+=n+1)o[_]=!o[_];for(;f--;)o[f]&&(l=f+1+s+l);alert(l)})(prompt().split(i=l=s=' '))

N = 23、K = 21の出力:

1 2 4 8 9 16 18 23  

Chromeでテストされていますが、派手な新しいECMAScript機能は使用していないため、どのブラウザーでも動作するはずです!

@tryingToGetProgrammingStrainghtが既にJavaScriptでエントリを送信したことは決してありませんが、N = 23、K = 21については、他のすべての人が取得していたのと同じ結果が得られなかったので、自分のバージョンを試してみてください。

編集:注釈付きのソース(これをもう一度見て、別の3文字を保存する場所を見つけたので、おそらくまだ改善できます...)

(function(g) {
    // initialise variables, set f to N
    o = [], f = g[0];

    // round counter
    // since ++' ' == 1 we can use the same variable set in args
    for (; i < g[1]; i++)
        // monkey counter, needs to be reset each round
        for (n = 0 ; n <= i; n++)
            // iterate to N and flip each Kth door
            for (_ = n; _ < f; _ += n + 1)
                // flip the bits (as undef is falsy, we don't need to initialise)
                // o[_] = !~~o[_]|0; // flips undef to 1
                o[_] = !o[_]; // but booleans are fine
    // decrement f to 0, so we don't need an additional counter
    for (;f--;)
        // build string in reverse order
        o[f] && (l = f + 1 + s + l); // l = (f + 1) + ' ' + l
    alert(l)
    // return l // use with test
// get input from user and store ' ' in variable for use later
})(prompt().split(i = l = s = ' '))
// })('23 21'.split(i = l = s = ' ')) // lazy...

// == '1 2 4 8 9 16 18 23  '; // test

よくできました!あなたも読めるとコメントしたバージョンを提供する場合、私はおそらくだろう+1
数学チラー

回答が更新されました!私はあなたの答えにコメントできないので、@ path411のコメントに追加するために、b = []を設定できます。空のインデックスは未定義のままで、さらに6文字節約できます!
ドムヘイスティングス

私は....すでにそれをした
数学チラー

1

ルビー-65文字

(1..n).each{|d|
t=0
(1..k).each{|m|t+=n-m+1 if d%m==0}
p d if t%2>0}

n = 23, k = 21 # => 1 2 4 8 9 16 18 23 

擬似コードでの計算は次のとおりです。

  • s(d)を、kラウンド後にドアdがタッチされた回数とします。
  • s(d)= sum(m = 1..m = k)(d%m == 0?(n-m + 1):0)
  • s(d)%2 = 1(または> 0)の場合、kラウンド後にドアdが開きます

s(d)の式が正しいと確信できない場合は、次のように見てください。

  • s(d、r)を、rラウンド後にドアdがタッチされた回数とします。
  • s(d、k)-s(d、k-1)= sum(m = 1、..、m = k)(d%m == 0?1:0)
  • s(d、k-1)-s(d、k-2)= sum(m = 1、..、m =(k-1))(d%m == 0?1:0)
  • ...
  • s(d、2)-s(d、1)= d%2 == 0?1:0
  • s(d、1)= 1
  • 両側を合計してs(d)の上記式を取得します。これはs(d、k)に等しくなります

とても簡潔です!どこでやるnkかかわらず、から来ますか?また、出力はスペースではなく改行で区切られているようです。
ポール・プレスティッジ

1

PowerShell:132

ゴルフコード:

$n,$k=(read-host)-split' ';0|sv($d=1..$n);1..$k|%{1..$_|%{$m=$_;$d|?{!($_%$m)}|%{sv $_ (!(gv $_ -Va))}}};($d|?{(gv $_ -Va)})-join' '

非ゴルフ、コメント付きコード:

# Get number of doors and monkeys from user as space-delimited string.
# Store number of doors as $n, number of monkeys as $k.
$n,$k=(read-host)-split' ';

# Store a list of doors in $d.
# Create each door as a variable set to zero.
0|sv($d=1..$n);

# Begin a loop for each round.
1..$k|%{

    # Begin a loop for each monkey in the current round.
    1..$_|%{

        # Store the current monkey's ID in $m.
        $m=$_;

        # Select only the doors which are evenly divisible by $m.
        # Pass the doors to a loop.
        $d|?{!($_%$m)}|%{

            # Toggle the selected doors.
            sv $_ (!(gv $_ -Va))
        }
    }
};

# Select the currently open doors.
# Output them as a space-delimited string.
($d|?{(gv $_ -Va)})-join' '

# Variables cleanup - don't include in golfed code.
$d|%{rv $_};rv n;rv d;rv k;rv m;

# NOTE TO SELF - Output for N=23 K=21 should be:
# 1 2 4 8 9 16 18 23

ああ、私は私の問題が何かを見る。私は質問を誤解しました-これは100 Lockersの問題ではありません。それは、ノッチを取りました!これにはもう少し作業が必要になります
...-Iszi

1
甘い!チャレンジの要件を適切に満たすように修正すると、最終的に6文字のゲインしか得られませんでした。
イッツィー

0

Powershell、66バイト

Cary Swovelandの回答に基づきます

param($n,$k)1..$n|?{$d=$_
(1..$k|?{($n-$_+1)*!($d%$_)%2}).Count%2}

テストスクリプト:

$f = {

param($n,$k)1..$n|?{$d=$_
(1..$k|?{($n-$_+1)*!($d%$_)%2}).Count%2}

}

@(
    ,(3, 3   , 1,2)
    ,(23, 21 , 1, 2, 4, 8, 9, 16, 18, 23)
) | % {
    $n,$k,$expected = $_
    $result = &$f $n $k
    "$("$result"-eq"$expected"): $result"
}

出力:

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