Recentemente, no Puzzling.SE, escrevi um problema sobre determinar quais duas garrafas de um número maior são envenenadas quando o veneno é ativado apenas se os dois componentes estiverem bêbados. Acabou sendo uma provação, com a maioria das pessoas conseguindo reduzir para 18 ou 19 prisioneiros usando algoritmos completamente diferentes.
A declaração do problema original é a seguinte:
Você é o governante de um reino medieval que adora dar festas. O cortesão que tentou envenenar uma de suas garrafas de vinho da última vez ficou furioso ao saber que você conseguiu identificar qual garrafa ele havia envenenado em mil com apenas dez prisioneiros.
Desta vez, ele é um pouco mais habilidoso. Ele desenvolveu um veneno composto
P
: um líquido binário que só é mortal quando dois componentes individualmente inofensivos se misturam; isso é semelhante a como o epóxi funciona. Ele enviou outro engradado de 1.000 garrafas de vinho. Um frasco tem componenteC_a
e outro tem componenteC_b
. (P = C_a + C_b
)Quem bebe os dois componentes morre na meia-noite da noite em que bebeu o componente final, independentemente de quando durante o dia ingeriu o líquido. Cada componente venenoso permanece no corpo até que o segundo componente seja ativado; portanto, se você beber um componente um dia e outro componente no dia seguinte, morrerá à meia-noite no final do segundo dia.
Você tem dois dias antes da sua próxima festa. Qual é o número mínimo de prisioneiros que você precisa usar para testar, a fim de identificar quais duas garrafas estão contaminadas e qual algoritmo você precisa seguir com esse número de prisioneiros?
Bônus
Além disso, suponha que você tivesse um limite fixo de 20 prisioneiros à sua disposição, qual é o número máximo de garrafas que você poderia testar teoricamente e chegar a uma conclusão precisa sobre quais garrafas foram afetadas?
Sua tarefa é criar um programa para resolver o problema do bônus. Dados os n
prisioneiros, seu programa criará uma programação de testes que será capaz de detectar as duas garrafas envenenadas entre as m
garrafas, sempre que m
for o maior possível.
Seu programa inicialmente terá como entrada o número N
, o número de prisioneiros. Em seguida, ele produzirá:
M
, o número de garrafas que você tentará testar. Essas garrafas serão rotuladas de1
paraM
.N
linhas, contendo os rótulos das garrafas que cada prisioneiro irá beber.
Seu programa tomará como entrada os prisioneiros que morreram no primeiro dia, com o prisioneiro na primeira linha 1
, na próxima linha 2
, etc. Em seguida, ele produzirá:
N
mais linhas, contendo os rótulos das garrafas que cada prisioneiro irá beber. Prisioneiros mortos terão linhas em branco.
Seu programa tomará como entrada os prisioneiros que morreram no segundo dia e produzirá dois números, A
eB
, representando quais as duas garrafas que seu programa acha que contêm o veneno.
Um exemplo de entrada para dois prisioneiros e quatro garrafas pode ir como tal, se garrafas 1
e 3
forem envenenadas:
> 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.
A programação de testes do seu programa deve determinar com êxito cada possível par de garrafas envenenadas para que seja um envio válido.
Seu programa será pontuado com os seguintes critérios, em ordem:
O número máximo de garrafas que pode discernir para o caso
N = 20
.O número de garrafas para o caso
N = 21
, e casos sucessivamente mais altos depois disso.O comprimento do código. (O código mais curto vence.)
fonte
Respostas:
Python 2.7.9 - 21 garrafas
Supondo que a especulação de ESultanik esteja certa sobre qual é a contribuição quando vários prisioneiros morrem
Algoritmo: todo prisioneiro bebe de todas as garrafas, exceto seu número (o primeiro prisioneiro não bebe a primeira garrafa). Se eles não morrerem, seu número de garrafa é envenenado. Se apenas um prisioneiro sobreviver, a garrafa extra será envenenada.
fonte
Perl 5 , 66 garrafas
(72 garrafas para 21 prisioneiros)
Os prisioneiros são divididos idealmente em 2 grupos. As garrafas são agrupadas em conjuntos.
Cada prisioneiro do grupo 1 beberá de todos os sets, exceto um. Haverá 1 ou 2 sobreviventes. Os 1 ou 2 sets que não foram tomados por eles continuarão no dia 2.
No dia 2, os prisioneiros restantes (incluindo os sobreviventes) bebem de todas as garrafas restantes, exceto uma.
Quando dois prisioneiros sobrevivem, as garrafas que não beberam são envenenadas.
Se apenas um prisioneiro permanecer, a garrafa que todos beberam também é suspeita.
O código inclui funcionalidade extra para facilitar o teste. Quando os frascos envenenados são adicionados como parâmetros adicionais, ele não solicita informações sobre quem morreu.
Teste
Teste sem entrada manual
fonte
Como é tradição, vou postar uma resposta de referência de último lugar.
Python - 7 garrafas
Faça com que cada prisioneiro beba um possível par de garrafas, exceto o par dos dois últimos. Se algum prisioneiro morre, o par que esse prisioneiro bebeu foram os envenenados. Caso contrário, foram as duas últimas garrafas que foram envenenadas.
Para lotes de pelo menos
n(n-1)/2 - 1
prisioneiros, você pode fazer atén
garrafas. Poisn = 7
, esse limite inferior é20
.Na verdade, precisamos apenas de um dia para que esta solução funcione. Uma solução de dois dias com um escopo semelhante pode levar até 20 garrafas
N = 20
, mas é muito trabalho para uma resposta trivial.fonte