Zehirli bir şarap testi zamanlayıcısı oluşturun


16

Son zamanlarda Puzzling.SE'de, daha fazla sayıda hangi iki şişenin zehirin sadece her iki bileşen sarhoşsa aktive edildiğinde zehirlendiğini belirleme konusunda yazdığım bir sorun vardı. Oldukça çileye dönüştü, çoğu insan onu tamamen farklı algoritmalar kullanarak 18 veya 19 mahkuma indirmeyi başardı.

Orijinal sorun bildirimi aşağıdaki gibidir:

Partileri atmayı seven bir ortaçağ krallığının hükümdarısınız. Şarap şişelerinizden birini son kez zehirlemeye çalışan kurye, 1000'den hangi şişeyi zehirlediğini sadece on mahkumla tanımayı başardığınızı öğrenmek için öfkeliydi.

Bu sefer biraz daha zeki. Kompozit bir zehir geliştirdi P: iki ayrı ayrı zararsız bileşen karıştığında ölümcül olan ikili bir sıvı; bu epoksinin nasıl çalıştığına benzer. Sana bir şişe daha 1000 şarap şişesi gönderdi. Bir şişenin bileşeni C_a, diğerinin bileşeni vardır C_b. ( P = C_a + C_b)

Her iki bileşeni de içen herkes, gece ne zaman sıvıyı emdiklerine bakılmaksızın, son bileşeni içtikleri gece yarısında iner. Her zehir bileşeni, ikinci bileşen etkinleşene kadar vücutta kalır, bu nedenle bir bileşeni bir gün ve başka bir bileşeni ertesi gün içerseniz, ikinci günün sonunda gece yarısı ölürsünüz.

Bir sonraki partinizden iki gün önce. Hangi iki şişenin lekelendiğini belirlemek için test için kullanmanız gereken asgari mahkum sayısı nedir ve bu sayıda mahkumla hangi algoritmayı takip etmeniz gerekir?


Bonus
Ayrıca, emrinizde sabit bir 20 mahkum sınırınız olduğunu varsayalım, teorik olarak test edebileceğiniz ve hangi şişelerin etkilendiği konusunda kesin bir sonuca varabileceğiniz maksimum şişe sayısı nedir?

Göreviniz bonus problemini çözmek için bir program oluşturmaktır. Verilen nmahkumlar, programı arasında iki zehirlenen şişeleri tespit etmek mümkün olacak bir test takvimi hazırlar mşişe, nerede mmümkün olduğunca büyük.

Programınız başlangıçta Nmahkum sayısını , sayısını girecektir. Sonra çıktı:

  • M, test etmeye çalışacağınız şişe sayısı. Bu şişeler gelen etiketlenir 1için M.

  • N her mahkumun içeceği şişelerin etiketlerini içeren çizgiler.

Programınız daha sonra ilk gün hangi mahkumların öldüğünü, ilk satırdaki mahkumun 1ve bir sonraki satırın2 vb. alınacaktır.

  • Nher mahkumun içeceği şişelerin etiketlerini içeren daha fazla satır. Ölü mahkersmların boş çizgileri olacak.

Programınız daha sonra ikinci günde mahkumların öldüğü bir girdi olarak alınacak ve iki sayı verilecektir, A ve Bprogram düşünür iki şişe zehir içeren temsil.

İki mahkum ve dört şişe için örnek bir girdi, şişeler 1ve 3zehirliyse şu şekilde olabilir:

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

Programınızın test programı, geçerli bir gönderim olması için her bir zehirli şişenin çiftini başarıyla belirlemelidir.

Programınız sırasıyla aşağıdaki ölçütlere göre puanlanacaktır:

  • Vaka için fark edebileceği maksimum şişe sayısı N = 20.

  • Dava için şişe sayısı N = 21ve bundan sonra daha yüksek vakalar.

  • Kodun uzunluğu. (Daha kısa kod kazanır.)


Bir günde birden fazla mahkum ölürse girdi nasıl görünecek? Örneklerinizden hiçbiri bu durumu kapsamıyor ve şartname benim için belirsiz.
ESultanik

Ölüden ayrılan mahkersmlar listesinin yer aldığı tek bir satır mı?
ESultanik

Daha kısa kod, şişe sayısından daha önemli mi? Son düzenlememde yaptığım gibi, bir şişe daha işlemek için kodun uzunluğunu artırmak verimli mi?
pppery

Şişe sayısı önceliklidir. Kodunuzu daha fazla şişeyi sıkmak için daha uzun ve daha karmaşık hale getirirseniz, bu verimli olur.
Joe Z.

Orijinal problemde sorunu çözmek için sadece 2 gün var. Meydan okuma için de kural bu mu? (olası çözümleri ciddi şekilde sınırlar, ancak sınırsız sayıda gün kolay olabilir)
LukStorms

Yanıtlar:


7

Python 2.7.9-21 şişe

ESultanik'in spekülasyonunun, birden fazla mahkum öldüğünde girdinin ne olduğu konusunda doğru olduğunu varsayarsak

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

Algoritma: her mahkum sayıları hariç her şişeden içiyor (1. mahkum ilk şişeyi içmiyor). Eğer ölmezlerse, sayı şişeleri zehirlenir. Sadece bir mahkum hayatta kalırsa, ekstra şişe zehirlenir.


3

Perl 5 , 66 şişe

(21 mahkum için 72 şişe)

Mahkumlar en iyi şekilde 2 gruba ayrılır. Şişeler setler halinde gruplandırılmıştır.

Grup 1'deki her mahkum biri hariç tüm setlerden içecektir. 1 ya da 2 kurtulan olacak. Onlar tarafından içmeyen 1 veya 2 set 2. güne devam edecek.

2. günde kalan mahkumlar (hayatta kalanlar dahil) biri hariç kalan tüm şişelerden içilir.
2 mahkum hayatta kaldığında içmedikleri şişeler zehirleniyor.
Sadece 1 mahkum kalırsa, o zaman hepsi içtiği şişe de şüphelidir.

Kod, testi kolaylaştırmak için ekstra işlevler içerir. Zehirlenen şişeler ek parametreler olarak eklendiğinde, kimin öldüğü hakkında girdi istemez.

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

Ölçek

$ 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

Manuel giriş olmadan test

$ 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

Gelenek gibi ben de son bir referans cevap göndereceğim.

Python - 7 şişe

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]

Her mahkumun son ikisinin çifti hariç olası bir çift şişe içmesini sağlayın. Eğer herhangi bir mahkum ölürse, mahkumun içtiği çift zehirlenmişti. Aksi takdirde, zehirlenen son iki şişe oldu.

En azından n(n-1)/2 - 1mahkumların tahsisleri için, nşişelere kadar yapabilirsiniz . Çünkü n = 7, bu alt sınır20 .

Bu çözümün çalışması için sadece bir güne ihtiyacımız var . Benzer bir kapsama sahip iki günlük bir çözüm 20 şişeye kadar çıkabilir N = 20, ancak önemsiz bir cevap için çok fazla iş.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.