Побудуйте планувальник для отруєних вин


16

Нещодавно в Puzzling.SE виникла проблема, про яку я писав про визначення того, які дві пляшки з більшої кількості отруєні, коли отрута активується, лише якщо обидва компоненти випиті. Це в кінцевому підсумку було досить тяжким випробуванням, і більшість людей встигли зменшити його до 18 або 19 в'язнів, використовуючи абсолютно різні алгоритми.

Оригінальний вислів проблеми такий:

Ви правитель середньовічного царства, який любить влаштовувати вечірки. Придворний, який останній раз намагався отруїти одну з ваших пляшок вина, розлютився, дізнавшись, що вам вдалося визначити, яку пляшку він отруїв із 1000 лише десятьма в'язнями.

Цього разу він трохи хитріший. Він розробив композитну отруту P : бінарну рідину, яка лише смертельна, коли змішуються два індивідуально нешкідливі компоненти; це схоже на те, як працює епоксидна смола. Він прислав вам ще одну ящик з 1000 пляшок вина. Одна пляшка має компонент, C_aа інша - компонент C_b. ( P = C_a + C_b)

Кожен, хто п’є обидва компоненти, загине від удару опівночі вночі, коли він випив остаточний компонент, незалежно від того, коли в день вбирали рідину. Кожен компонент отрути залишається в організмі, поки другий компонент не активізується, тому, якщо ви будете пити один компонент один день, а інший - наступний, ви помрете в півночі наприкінці другого дня.

Ви маєте два дні до наступної вечірки. Яку мінімальну кількість ув'язнених потрібно використовувати для тестування, щоб визначити, які дві пляшки забруднені та який алгоритм потрібно дотримуватись із цією кількістю ув'язнених?


Бонус
Крім того, припустимо, у вас було встановлене обмеження в 20 в’язнів, яке максимальне число пляшок ви могли теоретично випробувати і прийти до точного висновку про те, які пляшки постраждали?

Ваше завдання - створити програму для вирішення проблеми з бонусом. З огляду на nув'язнених, ваша програма розробить графік тестування, який зможе виявити дві отруєні пляшки серед mпляшок, де mце можливо більше.

Ваша програма спочатку буде приймати як вхід кількість N, кількість ув'язнених. Потім буде виведено:

  • M, кількість пляшок, яку ви спробуєте випробувати. Ці пляшки будуть марковані від 1до M.

  • 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

Кількість пляшок має пріоритет. Якщо ви зробите свій код довшим і складнішим, щоб вичавити більше пляшок, це буде продуктивним.
Джо З.

В оригінальній проблемі є лише 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 ув'язнених, отруєні пляшки, які вони не пили, отруюються.
Якщо залишається лише 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

Як традиція, я опублікую опорну відповідь останнього місця.

Пітон - 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 = 7ця нижня межа є 20.

Нам дійсно потрібен один день, щоб це рішення працювало. Дводенне рішення зі схожим розмахом може отримати до 20 пляшок N = 20, але це надто багато роботи для тривіальної відповіді.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.