No episódio Futurama, os membros da tripulação do Prisioneiro de Benda trocam de corpo entre si, com a intenção de que nenhum par de corpos pode ter suas mentes trocadas mais de uma vez.
Desafio
Escreva um programa ou função que aceite uma coleção válida de trocas mente-corpo que já ocorreram e produza um conjunto legal de trocas que retornarão cada mente ao seu corpo original. Os identificadores para essas coleções mente-corpo devem ser cadeias que não conterão novas linhas. Você pode adicionar até duas pessoas (com nome distinto) que não tiveram trocas anteriores no grupo de entrada. (Prova de que você só precisa de no máximo 2 órgãos adicionais). No entanto, você deve adicionar o número mínimo de pessoas necessárias para resolver o problema.
A entrada e a saída podem assumir qualquer forma clara; no entanto, nenhuma informação adicional também pode ser armazenada. Você pode assumir que é sempre válido. Isso é código de golfe, então o vencedor é o envio com o menor número de bytes.
Exemplos
[('A','B'),('C','D')] -> [('A','C'),('B','D'),('A','D'),('B','C')]
['A','B'] -> ['C','D','A','C','B','D','A','D','B','C']
[('A','B'),('C','D'),('A','C'),('A','D')] -> [('B', 'E'), ('A', 'E'), ('C', 'B'), ('C', 'E')]
"A\nB\nC\nD\n" -> "A\nC\nB\nD\nA\nD\nB\nC\n"
O do show:
[("Amy","Hubert"),("Bender","Amy"),("Hubert","Turanga"),("Amy","Wash Bucket"),("Wash Bucket","Nikolai"),("Phillip","John"),("Hermes","Turanga")]
A solução do programa, apresentada abaixo é inválida:
[("Clyde","Phillip"),("Ethan","John"),("Clyde","John"),("Ethan",Phillip"),("Clyde","Hubert"),("Ethan","Wash Bucket"),("Clyde","Leela"),("Ethan","Nikolai"),("Clyde","Hermes"),("Ethan","Bender"),("Clyde","Amy"),("Ethan","Hubert"),("Clyde","Wash Bucket")]
Isso é inválido porque Ethan e Clyde são desnecessários devido ao pouco uso de Fry Phillip, Zoidberg John e Hermes Hermes. Uma solução válida para este caso é fornecida abaixo:
[("Philip","Hubert"),("John","Wash Bucket"),("Philip","Turanga"),("John","Nikolai"),("Philip","Hermes"),("John","Bender"),("Philip","Amy"),("John","Hubert"),("Philip","Wash Bucket")]
Observe que existem claramente muitas respostas possíveis para qualquer entrada válida. Qualquer um é válido.
[('Nikolai', 'Phillip'), ('Nikolai', 'Hubert'), ('Nikolai', 'Turanga'), ('Nikolai', 'Bender'), ('Phillip', 'Amy'), ('John', 'Wash Bucket'), ('Nikolai', 'John'), ('Phillip', 'Wash Bucket'), ('Hubert', 'John'), ('Bender', 'Hermes')]
Respostas:
Caractere Python 3: 328 (lento), caractere 470 (rápido)
Provavelmente um pouco demais para uma resposta séria.
Código lento e curto:
d(u,s)
aplica uma trocas
parau
. No método principalf(Q)
, eu primeiro giro a lista de todas as pessoasn
usando operações definidas e convertendo o resultado em uma lista. Owhile 1
loop-obviamente não é um loop infinito. Nele, também tento resolver o problema usando as pessoas que tenhon
. Se não der certo, adiciono outra pessoa combinando todos os nomesn+=[''.join(n)]
. Portanto, owhile 1
loop é executado no máximo 3 vezes (veja a prova na pergunta).A solução do problema é feita com força bruta. Gero todos os swaps legais e tento todas as permutações
for t in permutations(i for i in combinations(n,2)if not set((i,i[::-1]))&set(Q))
. Se cada pessoa estiver em seu próprio corpo, retornarei a sequência de trocas.Uso:
O exemplo do futurama leva muito tempo. Existem 9 pessoas, então existem 36 swaps possíveis e 28 delas são legais. Então existem 26! permutações legais.
Código mais rápido
A função
f(Q)
possui uma abordagem de aprofundamento iterativo. Primeiro, tenta a profundidade = 0, depois a profundidade = 1, até a profundidade = (l * ll) // 2-len (Q), que é o número máximo de movimentos legais. Como o código mais lento, ele adiciona outra pessoa e tenta novamente.A função recursiva
r(n,u,Q,t,d)
tenta resolver a posição atualu
comd
swaps.n
é a posição resolvida,Q
a entrada se move et
os movimentos já feitos. Primeiro calcula um limite inferior de swapsm
necessários (resolvendo o estado com swaps legais e ilegais). Sem
== 0, todas as pessoas estão no corpo correto, por isso imprime a soluçãot
. Caso contrário, ele tenta todos os swaps possíveiss
, sem<d
(poda),d>1
(que já está incluído nom<d
,i//l<i%l
(não permitem swaps como('A','A')
ou('A','B')
e('B','A')
) enot set([s,s[::-1]])&set(Q+t)
(s
ainda não foi realizado).Uso:
Ele encontra as trocas ideais para o problema do futurama em cerca de 17 segundos no meu laptop usando pypy e cerca de 2 minutos sem pypy. Observe que os dois algoritmos produzem soluções diferentes, ao chamá-lo com o mesmo parâmetro. Isto é devido ao algoritmo de hash de um python-
set
.n
armazena a pessoa cada vez em uma ordem diferente. Portanto, o algoritmo pode ser mais rápido ou mais lento a cada execução.Edit: O caso de teste do futurama original estava errado, o caso de teste corrigido tem uma solução ideal de 9 em vez de 10 e, portanto, é mais rápido. 2 segundos com pypy, 7 segundos sem.
fonte