Xây dựng một lịch trình thử nghiệm rượu độc


16

Gần đây tại Puzzling.SE, có một vấn đề mà tôi đã viết về việc xác định hai chai nào trong số lớn hơn bị nhiễm độc khi chất độc chỉ kích hoạt nếu cả hai thành phần đều say. Nó đã kết thúc khá khó khăn, với hầu hết mọi người quản lý để đưa nó xuống tới 18 hoặc 19 tù nhân bằng các thuật toán hoàn toàn khác nhau.

Báo cáo vấn đề ban đầu như sau:

Bạn là người cai trị một vương quốc thời trung cổ, người thích ném tiệc. Cận thần đã cố gắng đầu độc một trong những chai rượu của bạn lần trước đã rất tức giận khi biết rằng bạn đã xác định được chai nào mà anh ta đã đầu độc trong số 1.000 chỉ với mười tù nhân.

Lần này anh ấy có một chút khéo léo hơn. Anh ta đã phát triển một chất độc hỗn hợp P : một chất lỏng nhị phân chỉ gây chết người khi hai thành phần vô hại riêng lẻ trộn lẫn; điều này tương tự như cách epoxy hoạt động. Anh ấy đã gửi cho bạn một thùng 1.000 chai rượu vang khác. Một chai có thành phần C_avà một chai khác có thành phần C_b. ( P = C_a + C_b)

Bất cứ ai uống cả hai thành phần sẽ chết vào đột quỵ vào nửa đêm vào đêm họ uống thành phần cuối cùng, bất kể khi nào trong ngày họ thấm chất lỏng. Mỗi thành phần độc hại tồn tại trong cơ thể cho đến khi thành phần thứ hai kích hoạt, vì vậy nếu bạn uống một thành phần một ngày và thành phần khác vào ngày hôm sau, bạn sẽ chết vào nửa đêm vào cuối ngày thứ hai.

Bạn có hai ngày trước bữa tiệc tiếp theo của bạn. Số lượng tù nhân tối thiểu bạn cần sử dụng để thử nghiệm là bao nhiêu để xác định hai chai nào bị nhiễm độc, và bạn cần tuân theo thuật toán nào với số tù nhân đó?


Phần thưởng
Ngoài ra, giả sử rằng bạn có giới hạn cố định là 20 tù nhân theo ý của bạn, số lượng chai tối đa bạn có thể kiểm tra về mặt lý thuyết và đưa ra kết luận chính xác về việc chai nào bị ảnh hưởng?

Nhiệm vụ của bạn là xây dựng một chương trình để giải quyết vấn đề tiền thưởng. Đối với các ntù nhân, chương trình của bạn sẽ đưa ra một lịch trình thử nghiệm để có thể phát hiện hai chai bị nhiễm độc trong số các mchai, nơi mcàng lớn càng tốt.

Chương trình của bạn ban đầu sẽ lấy đầu vào là số N, số tù nhân. Sau đó nó sẽ xuất ra:

  • M, số lượng chai bạn sẽ cố gắng kiểm tra. Những chai sẽ được dán nhãn từ 1đến M.

  • N dòng, chứa nhãn của các chai mỗi tù nhân sẽ uống.

Chương trình của bạn sau đó sẽ lấy đầu vào mà tù nhân đã chết vào ngày đầu tiên, với tù nhân ở dòng đầu tiên 1, dòng tiếp theo 2, v.v. Sau đó, nó sẽ xuất ra:

  • Nnhiều dòng hơn, chứa nhãn của các chai mỗi tù nhân sẽ uống. Những tù nhân chết sẽ có những dòng trống.

Chương trình của bạn sau đó sẽ lấy đầu vào là tù nhân đã chết vào ngày thứ hai và xuất ra hai số, AB, đại diện cho hai chai mà chương trình của bạn nghĩ có chứa chất độc.

Một ví dụ đầu vào cho hai tù nhân và bốn chai có thể đi như vậy, nếu chai 13bị nhiễm độc:

> 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.

Lịch trình thử nghiệm của chương trình của bạn phải xác định thành công từng cặp chai bị nhiễm độc có thể để nó là một đệ trình hợp lệ.

Chương trình của bạn sẽ được chấm theo các tiêu chí sau, theo thứ tự:

  • Số lượng chai tối đa nó có thể nhận thấy cho trường hợp N = 20.

  • Số lượng chai cho các trường hợp N = 21, và liên tiếp các trường hợp cao hơn sau đó.

  • Độ dài của mã. (Mã ngắn hơn sẽ thắng.)


Làm thế nào đầu vào sẽ trông như thế nào nếu nhiều hơn một tù nhân chết trong một ngày? Không có ví dụ nào của bạn bao gồm trường hợp đó và đặc điểm kỹ thuật này không rõ ràng đối với tôi.
ESultanik 16/07/2015

Đây có phải là một dòng duy nhất với một danh sách các tù nhân bị ngăn cách không gian?
ESultanik 16/07/2015

Có mã ngắn hơn quan trọng hơn số lượng chai? Có hiệu quả không khi tăng độ dài của mã để làm cho nó xử lý thêm một chai, như tôi đã làm trong lần chỉnh sửa gần đây?
pppery

Số lượng chai được ưu tiên. Nếu bạn làm cho mã của mình dài hơn và phức tạp hơn để ép nhiều chai hơn, điều đó có hiệu quả.
Joe Z.

Trong bài toán ban đầu chỉ có 2 ngày để giải bài toán. Có phải đó cũng là quy tắc cho thử thách? (nó giới hạn nghiêm ngặt các giải pháp có thể, tuy nhiên số lượng ngày không giới hạn sẽ trở nên dễ dàng)
LukStorms

Câu trả lời:


7

Python 2.7.9 - 21 chai

Giả sử rằng suy đoán của ESultanik là đúng về đầu vào là gì khi nhiều tù nhân chết

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])

Thuật toán: mọi tù nhân đều uống từ mỗi chai trừ số của họ (tù nhân thứ nhất không uống chai đầu tiên). Nếu họ không chết, chai số của họ bị nhiễm độc. Nếu chỉ có một tù nhân sống sót, chai thêm bị nhiễm độc.


3

Perl 5 , 66 chai

(72 chai cho 21 tù nhân)

Các tù nhân được chia tối ưu thành 2 nhóm. Các chai được nhóm theo bộ.

Mỗi tù nhân của nhóm 1 sẽ uống từ tất cả các bộ trừ một. Sẽ có 1 hoặc 2 người sống sót. 1 hoặc 2 bộ không được họ uống sẽ tiếp tục đến ngày thứ 2.

Vào ngày thứ 2, các tù nhân còn lại (bao gồm cả những người sống sót) uống từ tất cả các chai còn lại trừ một chai.
Khi 2 tù nhân sống sót sau đó những chai họ không uống bị nhiễm độc.
Nếu chỉ còn 1 tù nhân thì cái chai mà tất cả họ uống cũng đáng nghi.

Mã này bao gồm chức năng bổ sung để tạo điều kiện kiểm tra. Khi các chai bị nhiễm độc được thêm vào dưới dạng tham số bổ sung, thì nó sẽ không hỏi về đầu vào về người đã chết.

($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"

Kiểm tra

$ 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

Kiểm tra mà không cần nhập thủ công

$ 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

Như truyền thống, tôi sẽ đăng một câu trả lời tham khảo cuối cùng.

Python - 7 chai

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]

Làm cho mỗi tù nhân uống một cặp chai có thể ngoại trừ cặp hai chai cuối cùng. Nếu bất kỳ tù nhân nào chết, cặp mà tù nhân đó uống là những người bị đầu độc. Nếu không, đó là hai chai cuối cùng đã bị nhiễm độc.

Đối với các khoản giao của ít nhất là n(n-1)/2 - 1tù nhân, bạn có thể làm tới nchai. Đối với n = 7, giới hạn thấp hơn này là 20.

Chúng tôi thực sự chỉ cần một ngày để giải pháp này hoạt động. Một giải pháp hai ngày với phạm vi tương tự có thể nhận được tới 20 chai N = 20, nhưng đó là quá nhiều công việc cho một câu trả lời tầm thường.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.