สร้างกำหนดการทดสอบไวน์ที่มีพิษ


16

เมื่อเร็ว ๆ นี้ที่ Puzzling.SE มีปัญหาที่ฉันเขียนเกี่ยวกับการพิจารณาว่าขวดสองขวดจากจำนวนที่มากกว่านั้นถูกวางยาพิษเมื่อพิษเปิดใช้งานเฉพาะในกรณีที่ส่วนประกอบทั้งสองเมา ในที่สุดมันก็กลายเป็นเรื่องยากลำบากโดยคนส่วนใหญ่จัดการเพื่อให้นักโทษลง 18 หรือ 19 คนโดยใช้อัลกอริทึมที่แตกต่างกันโดยสิ้นเชิง

คำแถลงปัญหาเดิมมีดังต่อไปนี้:

คุณคือผู้ปกครองของอาณาจักรยุคกลางที่ชอบปาร์ตี้ขว้างปา ข้าราชบริพารที่พยายามวางยาพิษขวดไวน์ของคุณครั้งหนึ่งก็โกรธที่จะรู้ว่าคุณจัดการเพื่อระบุขวดที่เขาวางยาพิษจาก 1,000 ขวดกับนักโทษเพียงสิบคน

เวลานี้เขาช่างเก่งขึ้น เขาได้พัฒนาพิษผสม P : ของเหลวแบบไบนารีที่อันตรายถึงตายเมื่อส่วนประกอบที่ไม่เป็นอันตรายสองรายการผสมกัน มันคล้ายกับการทำงานของอีพอกซี เขาส่งลังอีก 1,000 ขวดให้คุณ ขวดหนึ่งมีองค์ประกอบและอีกคนหนึ่งมีองค์ประกอบC_a C_b( P = C_a + C_b)

ทุกคนที่ดื่มส่วนประกอบทั้งสองจะตายในจังหวะของเที่ยงคืนในตอนกลางคืนพวกเขาดื่มส่วนประกอบสุดท้ายโดยไม่คำนึงถึงว่าเมื่อใดในวันที่พวกเขาดูดของเหลว ส่วนประกอบที่เป็นพิษแต่ละชิ้นจะยังคงอยู่ในร่างกายจนกว่าส่วนประกอบที่สองจะทำงานดังนั้นหากคุณดื่มหนึ่งองค์ประกอบในวันหนึ่งและอีกองค์ประกอบต่อไปคุณจะตายในเวลาเที่ยงคืนในตอนท้ายของวันที่สอง

คุณมีสองวันก่อนงานปาร์ตี้ครั้งต่อไปของคุณ จำนวนผู้ต้องขังขั้นต่ำที่คุณต้องใช้ในการทดสอบคืออะไรเพื่อระบุขวดสองขวดที่เสียและขั้นตอนวิธีใดที่คุณต้องปฏิบัติตามกับจำนวนนักโทษ


โบนัส
นอกจากนี้สมมติว่าคุณมีผู้ต้องขังที่ จำกัด จำนวน 20 คนจำนวนขวดสูงสุดที่คุณสามารถทดสอบได้ในทางทฤษฎีและมาถึงข้อสรุปที่แม่นยำเกี่ยวกับขวดที่ได้รับผลกระทบ

งานของคุณคือสร้างโปรแกรมเพื่อแก้ปัญหาโบนัส ได้รับnนักโทษโปรแกรมจะประดิษฐ์กำหนดการทดสอบว่าจะสามารถที่จะตรวจสอบทั้งสองขวดยาพิษในหมู่mขวดที่mมีขนาดใหญ่ที่สุดเท่าที่ทำได้

ในตอนแรกโปรแกรมของคุณจะป้อนหมายเลขNจำนวนนักโทษ จากนั้นจะแสดงผลลัพธ์:

  • Mจำนวนขวดที่คุณจะพยายามทดสอบ ขวดเหล่านี้จะมีข้อความจากไป1M

  • N บรรทัดที่มีฉลากของขวดนักโทษแต่ละคนจะดื่ม

โปรแกรมของคุณจะใช้เป็นข้อมูลที่นักโทษเสียชีวิตในวันแรกโดยมีนักโทษอยู่ที่บรรทัดแรกบรรทัด1ถัดไป2เป็นต้นจากนั้นรายการจะแสดงผลลัพธ์:

  • Nบรรทัดเพิ่มเติมที่ประกอบด้วยฉลากของขวดแต่ละนักโทษจะดื่ม นักโทษที่ตายจะมีเส้นว่าง

โปรแกรมของคุณจะใช้เป็นข้อมูลที่นักโทษเสียชีวิตในวันที่สองและส่งออกตัวเลขสองจำนวนAและBแสดงว่าขวดใดที่โปรแกรมของคุณคิดว่ามีพิษสองขวด

ตัวอย่างอินพุตสำหรับนักโทษสองคนและสี่ขวดอาจเป็นเช่นนี้หากขวด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และกรณีที่สูงขึ้นอย่างต่อเนื่องหลังจากนั้น

  • ความยาวของรหัส (รหัสที่สั้นกว่าจะชนะ)


ข้อมูลจะดูอย่างไรหากมีนักโทษมากกว่าหนึ่งคนเสียชีวิตในวันเดียว? ตัวอย่างของคุณไม่ครอบคลุมถึงกรณีนั้นและข้อกำหนดไม่ชัดเจนสำหรับฉัน
ESultanik

มันเป็นบรรทัดเดียวที่มีรายชื่อนักโทษแยกจากกันที่เสียชีวิตหรือไม่?
ESultanik

รหัสที่สั้นกว่าสำคัญกว่าจำนวนขวดหรือไม่ มันมีประสิทธิผลหรือไม่ที่จะเพิ่มความยาวของรหัสเพื่อให้มันจัดการกับขวดอีกหนึ่งขวดอย่างที่ฉันทำในการแก้ไขล่าสุดของฉัน
pppery

จำนวนขวดมีความสำคัญ หากคุณทำรหัสของคุณให้ยาวขึ้นและซับซ้อนยิ่งขึ้นเพื่อบีบขวดให้มากขึ้นนั่นจะเป็นประโยชน์
Joe 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 ขวด

(72 ขวดสำหรับนักโทษ 21 คน)

นักโทษถูกแบ่งออกเป็น 2 กลุ่มอย่างเหมาะสมที่สุด ขวดถูกจัดกลุ่มเป็นชุด

นักโทษกลุ่มที่ 1 แต่ละคนจะดื่มจากทุกชุดยกเว้นหนึ่งชุด จะมีผู้รอดชีวิต 1 หรือ 2 คน ชุด 1 หรือ 2 ชุดที่ไม่ได้ดื่มจะถูกดำเนินการจนถึงวันที่ 2

ในวันที่ 2 นักโทษที่เหลืออยู่ (รวมถึงผู้รอดชีวิต) ดื่มจากขวดที่เหลือทั้งหมดยกเว้นหนึ่งขวด
เมื่อนักโทษ 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]

ทำให้นักโทษแต่ละคนดื่มขวดหนึ่งคู่ที่เป็นไปได้ยกเว้นคู่สุดท้าย หากนักโทษคนใดเสียชีวิตคู่ที่นักโทษคนนั้นดื่มเป็นคนที่วางยาพิษ มิฉะนั้นมันเป็นขวดสองขวดสุดท้ายที่ถูกวางยาพิษ

สำหรับการจัดสรรn(n-1)/2 - 1นักโทษอย่างน้อยคุณสามารถทำnขวดได้ สำหรับนี้เป็นวงเงินที่ต่ำกว่าn = 720

ที่จริงแล้วเราต้องการเพียงหนึ่งวันเพื่อให้วิธีนี้ใช้งานได้ โซลูชันสองวันที่มีขอบเขตที่คล้ายกันอาจได้รับมากถึง 20 ขวดN = 20แต่มันใช้งานได้มากเกินไปสำหรับคำตอบที่ไม่สำคัญ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.