汚染されたワインのテストスケジューラを構築する


16

最近、Puzzling.SEで、両方のコンポーネントが飲まれた場合にのみ毒が活性化する場合、より多くのボトルのうち2本が毒されるかどうかを判断することについて書いた問題がありました。最終的にはかなりの試練となり、ほとんどの人が完全に異なるアルゴリズムを使用して18人または19人の囚人に追い詰めました。

元の問題ステートメントは次のとおりです。

あなたはパーティーを投げるのが大好きな中世の王国の支配者です。前回あなたのワインボトルの1つを毒物にしようとした宮廷人は、あなたがたった10人の囚人で1,000本のうちどのボトルに毒物を入れたのかを特定できたことに激怒しました。

今回は彼は少し巧妙です。彼は複合毒を 開発しましたP。2つの個別に無害な成分が混合した場合にのみ致命的なバイナリ液体。これは、エポキシの仕組みに似ています。彼はあなたに1,000本のワインボトルの箱を送りました。1つのボトルにはコンポーネントがC_aあり、別のボトルにはコンポーネントがありますC_b。(P = C_a + C_b

両方の成分を飲んだ人は誰でも、液体を吸収した日のいつでも、最終成分を飲んだ夜の真夜中に死にます。各毒成分は、2番目の成分が活性化するまで体内に留まるため、ある成分を次の日に飲み、別の成分を翌日飲むと、2日目の終わりの深夜に死んでしまいます。

次のパーティーの2日前があります。どの2本のボトルが汚染されているかを特定するためにテストに使用する必要がある囚人の最小数と、その数の囚人を追跡するために必要なアルゴリズムは何ですか?


ボーナス
さらに、20人の囚人を自由に使用できる固定限度があると仮定します。理論的にテストして、影響を受けたボトルについて正確な結論を出すことができるボトルの最大数はいくつですか。

あなたの仕事は、ボーナスの問題を解決するプログラムを構築することです。与えられたn囚人たちが、あなたのプログラムがうちの2本の毒の瓶を検出することができますテストスケジュール考案ますmボトルを、どこmできるだけ大きいです。

あなたのプログラムは、最初に入力としてN、囚人の数、つまり数を取ります。次に出力されます:

  • M、テストしようとするボトルの数。これらのボトルにはからのラベルが付け1られMます。

  • N 各囚人が飲むボトルのラベルを含む行。

プログラムは、最初の行にある囚人1、次の行にある囚人など、初日に死亡した囚人を入力として受け取ります2。その後、次のように出力されます。

  • N各囚人が飲むボトルのラベルを含むより多くの行。死んだ囚人には空白行があります。

プログラムは、2日目に死亡した囚人を入力として受け取り、2つの数字を出力します。AそしてB、プログラムが毒を含むと考える2つのボトルを表します。

2人の囚人と4つのボトルに対する入力例は、ボトルが毒されている場合、次のように1なり3ます。

> 2      // INPUT: 2 prisoners
4        // OUTPUT: 4 bottles
1 2 3    // OUTPUT: prisoner 1 will drink 1, 2, 3
1 4      // OUTPUT: prisoner 2 will drink 1, 4
> 1      // INPUT: only the first prisoner died
         // OUTPUT: prisoner 1 is dead, he can't drink any more bottles
3        // OUTPUT: prisoner 2 drinks bottle 3
> 2      // INPUT: prisoner 2 died
1 3      // OUTPUT: therefore, the poisoned bottles are 1 and 3.

The above algorithm may not actually work in all
cases; it's just an example of input and output.

プログラムのテストスケジュールが有効な提出であるためには、有毒なボトルの各ペアを正常に決定する必要があります。

プログラムは、次の基準で順番に採点されます。

  • ケースで識別できるボトルの最大数N = 20

  • ケースのボトルの数N = 21、およびその後の連続して高いケース。

  • コードの長さ。(短いコードが優先されます。)


1日に複数の囚人が死亡した場合、入力はどのように見えますか?どちらの例もその場合をカバーしておらず、仕様は私にはあいまいです。
ESultanik

死亡した囚人のリストがスペースで区切られた単一行ですか?
ESultanik

短いコードはボトルの数よりも重要ですか?最近の編集で行ったように、コードの長さを増やしてもう1本のボトルを処理できるようにすることは生産的ですか?
pppery

ボトル数が優先されます。コードをより長く、より複雑にして、より多くのボトルを詰め込めば、生産的です。
ジョーZ.

元の問題では、問題を解決するのに2日しかありません。それもチャレンジのルールですか?(可能なソリューションを厳しく制限しますが、無制限の日数は簡単です)
-LukStorms

回答:


7

Python 2.7.9 — 21本

ESultanikの推測は、複数の囚人が死んだときのインプットが正しいと仮定している

r=raw_input;s=str;j=s.join;p=int(r());z=range;q=z(p);x=z(p+1)
print s(p+1)+"\n"+j("\n",(j(" ",(s(a) for a in x if a!=b)) for b in q))
v=r().split();d=[s(a) for a in q if s(a) not in v];d+=[p]if len(d)==1 else [];
print "\n"*p,;r();print j(" ",[s(a) for a in d])

アルゴリズム:すべての囚人は、番号以外のすべてのボトルから飲みます(最初の囚人は最初のボトルを飲みません)。彼らが死ななければ、彼らのナンバーボトルは毒されます。1人の囚人だけが生き残った場合、余分なボトルは毒されます。


3

Perl 5、66

(21人の囚人に72ボトル)

囚人は最適に2つのグループに分けられます。ボトルはセットにグループ化されています。

グループ1の各囚人は、1セットを除くすべてのセットから飲みます。1人または2人の生存者がいます。彼らが飲まなかった1または2セットは2日目まで続きます。

2日目に、残りの囚人(生存者を含む)は、1本を除く残りのすべてのボトルから飲みます。
2人の囚人が生き残ると、飲まなかったボトルが毒されます。
囚人が1人しか残っていない場合、彼らが飲んだ瓶も疑わしいです。

コードには、テストを容易にするための追加機能が含まれています。ポイズニングされたボトルが追加のパラメーターとして追加された場合、誰が死亡したかについての入力を求めません。

($p,$f,$l)=@ARGV;
$p=9if!$p;
$m=$p-(2*int($p/4))+1;
$n=$p-$m+2;
$b=$m*(($n+1)/2);
@M=(1..$m);
print"Prisoners: $p\nBottles: $b\n";
# building the sets of items
for$x(@M){
    $j=$k+1;$k+=($n+1)/2;
    $s=join",",($j..$k);
    $A[$x]=$s
}
# assigning the sets to the actors
for$x(@M){
    @T=();
    for$j(@M){if($x!=$j){push@T,split/,/,$A[$j]}}
    print"Prisoner $x drinks @T\n";
    $B[$x]=join",",@T
}
if(!$f||!$l){
    # manual input
    print"Who dies: ";
    $_=<STDIN>;chomp;
    @D=split/ /;
    %h=map{($_,1)}@D;
    @S=grep{!$h{$_}}(@M)
} 
else{
    # calculate who dies based on the parameters
    for$x(@M){
        $d=0;
        map{if($_==$f||$_==$l){$d++}}split/,/,$B[$x];
        if($d>1){push@D,$x}else{push@S,$x}
    }
}
for(@D){print"Prisoner $_ dies\n"}

# calculate the remaining items
for(@S){push@R,split/,/,$A[$_]}@R=sort{$a<=>$b}grep{!$g{$_}++}@R;

# different set of actors if there were 1 or 2 sets remaining
if(@S>1){@S=($S[0],$m+1..$p,$S[1],0)}else{@S=($m+1..$p)};

$i=0;@B=@D=();
# assign an item to each actor
for$x(@S){
    @T=();
    for($j=0;$j<@R;$j++){
        if($i!=$j){push@T,$R[$j]}
    }$i++;
    print"Prisoner $x drinks @T\n"if$x>0;
    $B[$x]=join",",@T
}

if(!$f||!$l){
    # manual input
    print"Who dies: ";
    $_=<STDIN>;chomp;
    @D=sort split/ /;
    if(@D<@S-1){push@D,0} # because the set that noone drinks isn't manually put in
    %h=map{($_,1)}@D;
    @L=grep{!$h{$_}}(@S);
}
else{
    # calculate who dies based on the parameters
    @D=();
    for$x(@S){
        $d=0;
        map{if($_==$f||$_==$l){$d++}}split/,/,$B[$x];
        if($d>1){push@D,$x}else{push@L,$x}
    }
}

for(@D){print"Prisoner $_ dies\n"if$_>0}

# calculate the remaining items
for(@L){push@F,split/,/,$B[$_]}
map{$c{$_}++}@F;
for(keys%c){push(@Z,$_)if$c{$_}==1}
@R=sort{$a<=>$b}@Z;

print"Suspected bottles: @R"

テスト

$ perl poisened_bottles.pl 20
Prisoners: 20
Bottles: 66
Prisoner 1 drinks 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
Prisoner 2 drinks 1 2 3 4 5 6 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
Prisoner 3 drinks 1 2 3 4 5 6 7 8 9 10 11 12 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
Prisoner 4 drinks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
Prisoner 5 drinks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
Prisoner 6 drinks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
Prisoner 7 drinks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
Prisoner 8 drinks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
Prisoner 9 drinks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 55 56 57 58 59 60 61 62 63 64 65 66
Prisoner 10 drinks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 61 62 63 64 65 66
Prisoner 11 drinks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
Who dies: 2 3 4 5 6 7 8 9 10
Prisoner 2 dies
Prisoner 3 dies
Prisoner 4 dies
Prisoner 5 dies
Prisoner 6 dies
Prisoner 7 dies
Prisoner 8 dies
Prisoner 9 dies
Prisoner 10 dies
Prisoner 1 drinks 2 3 4 5 6 61 62 63 64 65 66
Prisoner 12 drinks 1 3 4 5 6 61 62 63 64 65 66
Prisoner 13 drinks 1 2 4 5 6 61 62 63 64 65 66
Prisoner 14 drinks 1 2 3 5 6 61 62 63 64 65 66
Prisoner 15 drinks 1 2 3 4 6 61 62 63 64 65 66
Prisoner 16 drinks 1 2 3 4 5 61 62 63 64 65 66
Prisoner 17 drinks 1 2 3 4 5 6 62 63 64 65 66
Prisoner 18 drinks 1 2 3 4 5 6 61 63 64 65 66
Prisoner 19 drinks 1 2 3 4 5 6 61 62 64 65 66
Prisoner 20 drinks 1 2 3 4 5 6 61 62 63 65 66
Prisoner 11 drinks 1 2 3 4 5 6 61 62 63 64 66
Who dies: 1 12 14 15 16 17 18 20 11
Prisoner 1 dies
Prisoner 11 dies
Prisoner 12 dies
Prisoner 14 dies
Prisoner 15 dies
Prisoner 16 dies
Prisoner 17 dies
Prisoner 18 dies
Prisoner 20 dies
Suspected bottles: 3 63

手動入力なしのテスト

$ perl poisened_bottles.pl 7 2 5
Prisoners: 7
Bottles: 12
Prisoner 1 drinks 3 4 5 6 7 8 9 10 11 12
Prisoner 2 drinks 1 2 5 6 7 8 9 10 11 12
Prisoner 3 drinks 1 2 3 4 7 8 9 10 11 12
Prisoner 4 drinks 1 2 3 4 5 6 9 10 11 12
Prisoner 5 drinks 1 2 3 4 5 6 7 8 11 12
Prisoner 6 drinks 1 2 3 4 5 6 7 8 9 10
Prisoner 2 dies
Prisoner 4 dies
Prisoner 5 dies
Prisoner 6 dies
Prisoner 1 drinks 2 5 6
Prisoner 7 drinks 1 5 6
Prisoner 3 drinks 1 2 6
Prisoner 1 dies
Suspected bottles: 2 5

2

伝統のように、私は最後の場所の参照の答えを投稿します。

Python — 7ボトル

prisoners = int(raw_input())

bottles = 0
while (bottles * (bottles + 1) / 2 - 1) <= prisoners:
    bottles += 1

print bottles

pairs = []
for i in range(bottles):
    for j in range(i + 1, bottles):
        pairs += [str(i + 1) + " " + str(j + 1)]

for i in range(prisoners):
    if i < len(pairs):
        print pairs[i]
    else:
        print

dead_prisoner = raw_input()

for i in range(prisoners):
    print
raw_input() # discard the second day entirely

if dead_prisoner == "":
    print pairs[-1]
else:
    print pairs[int(dead_prisoner) - 1]

最後の2組を除き、各囚人に1組のボトルを飲ませます。囚人が死亡した場合、その囚人が飲んだのは毒された者でした。それ以外の場合は、最後の2本が毒殺されました。

少なくともn(n-1)/2 - 1囚人の割り当てについては、nボトルまで行うことができます。の場合n = 7、この下限は20です。

このソリューションが機能するのに実際に必要なのは1日だけです。同様のスコープを持つ2日間のソリューションは、最大20本のボトルを取得する可能性がありますN = 20が、些細な答えにはあまりにも手間がかかります。

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