Ostatnio w Puzzling.SE napotkałem problem związany z określeniem, które dwie butelki z większej liczby są zatrute, gdy trucizna aktywuje się tylko wtedy, gdy oba składniki są pijane. Skończyło się to dość ciężką próbą, a większość ludzi zdołała sprowadzić go do 18 lub 19 więźniów przy użyciu zupełnie innych algorytmów.
Oryginalna deklaracja problemu jest następująca:
Jesteś władcą średniowiecznego królestwa, który uwielbia organizować przyjęcia. Dworzanin, który ostatni raz próbował otruć jedną z twoich butelek wina, był wściekły, gdy dowiedział się, że udało ci się zidentyfikować, którą butelkę zatruł na 1000 z zaledwie dziesięcioma więźniami.
Tym razem jest trochę bardziej sprytny. Opracował złożoną truciznę
P
: podwójny płyn, który jest śmiertelny tylko wtedy, gdy zmieszają się dwa indywidualnie nieszkodliwe składniki; jest to podobne do działania żywicy epoksydowej. Wysłał ci kolejną skrzynię 1000 butelek wina. Jedna butelka ma składnik,C_a
a druga ma składnikC_b
. (P = C_a + C_b
)Każdy, kto pije oba składniki, umrze po północy w noc, w której wypił ostatni składnik, niezależnie od tego, kiedy w ciągu dnia wchłonął płyn. Każdy składnik trucizny pozostaje w ciele, dopóki drugi składnik nie zostanie aktywowany, więc jeśli wypijesz jeden składnik jednego dnia, a drugi następnego, umrzesz o północy pod koniec drugiego dnia.
Masz dwa dni do następnej imprezy. Jaka jest minimalna liczba więźniów, których należy użyć do testowania, aby zidentyfikować, które dwie butelki są skażone, i jakiego algorytmu należy przestrzegać przy tej liczbie więźniów?
Premia
Dodatkowo, przypuśćmy, że dysponowałeś stałym limitem 20 więźniów, jaka jest maksymalna liczba butelek, które możesz teoretycznie przetestować i dojść do dokładnego wniosku, na które butelki miało to wpływ?
Twoim zadaniem jest zbudowanie programu do rozwiązania problemu bonusowego. Biorąc pod uwagę n
więźniów, twój program opracuje harmonogram testów, który będzie w stanie wykryć dwie zatrute butelki wśród m
butelek, gdzie m
są one tak duże, jak to możliwe.
Twój program początkowo przyjmie jako dane wejściowe liczbę N
, liczbę więźniów. Następnie wyświetli:
M
, liczba butelek, które spróbujesz przetestować. Te butelki będą oznaczone od1
doM
.N
linie zawierające etykiety butelek, które wypije każdy więzień.
Twój program pobierze następnie dane wejściowe, którzy więźniowie zmarli pierwszego dnia, z więźniem w pierwszej linii 1
, w kolejnej linii 2
itd. Następnie wyświetli:
N
więcej linii, zawierających etykiety butelek, które każdy więzień wypije. Martwi więźniowie będą mieli puste linie.
Twój program następnie weźmie pod uwagę, którzy więźniowie zmarli drugiego dnia, i wyśle dwie liczby, A
i B
reprezentując, które dwie butelki twój program uważa za truciznę.
Przykładem wejście dla dwóch więźniów i cztery butelki może iść jako takie, czy butelek 1
i 3
są zatrute:
> 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.
Harmonogram testów Twojego programu musi z powodzeniem określać każdą możliwą parę zatrutych butelek, aby mogła być ważna.
Twój program będzie oceniany według następujących kryteriów, w kolejności:
Maksymalna liczba butelek, jaką może rozpoznać dla skrzynki
N = 20
.Liczba butelek w skrzynce
N = 21
, a następnie kolejne skrzynie.Długość kodu. (Wygrywa krótszy kod).
źródło
Odpowiedzi:
Python 2.7.9 - 21 butelek
Zakładając, że spekulacje ESultanika są słuszne na temat wkładu, gdy wielu więźniów umiera
Algorytm: każdy więzień pije z każdej butelki oprócz swojej liczby (pierwszy więzień nie pije pierwszej butelki). Jeśli nie umrą, ich butelka z liczbami jest zatruta. Jeśli przeżyje tylko jeden więzień, dodatkowa butelka jest zatruta.
źródło
Perl 5 , 66 butelek
(72 butelki dla 21 więźniów)
Więźniowie są optymalnie podzieleni na 2 grupy. Butelki są pogrupowane w zestawy.
Każdy więzień z grupy 1 będzie pił ze wszystkich zestawów oprócz jednego. Będzie 1 lub 2 ocalałych. 1 lub 2 zestawy, które nie zostały wypite, będą kontynuowane do drugiego dnia.
W drugim dniu pozostali więźniowie (w tym ci, którzy przeżyli) piją ze wszystkich pozostałych butelek oprócz jednej.
Kiedy 2 więźniów przeżyje, butelki, których nie wypili, są zatrute.
Jeśli pozostanie tylko 1 więzień, to butelka, którą wszyscy wypili, jest również podejrzana.
Kod zawiera dodatkową funkcjonalność ułatwiającą testowanie. Po dodaniu zatłoczonych butelek jako dodatkowych parametrów, nie poprosi on o informację o tym, kto zmarł.
Test
Test bez ręcznego wprowadzania danych
źródło
Zgodnie z tradycją opublikuję referencyjną odpowiedź na ostatnie miejsce.
Python - 7 butelek
Niech każdy więzień wypije jedną możliwą parę butelek, z wyjątkiem pary dwóch ostatnich. Jeśli któryś z więźniów umrze, para, którą ten więzień pił, była zatruta. W przeciwnym razie zatrute zostały dwie ostatnie butelki.
Przydziały dla co najmniej
n(n-1)/2 - 1
więźniów można zrobić don
butelek. Ponieważn = 7
ten dolny limit wynosi20
.Potrzebujemy tylko jednego dnia, aby to rozwiązanie zadziałało. Dwudniowe rozwiązanie o podobnym zakresie może
N = 20
kosztować nawet 20 butelek , ale jest to zbyt wiele pracy, by uzyskać banalną odpowiedź.źródło