Cattive notizie, qualcuno


10

Nell'episodio di Futurama, i membri dell'equipaggio del Prigioniero di Benda si scambiano i corpi l'uno con l'altro, con la cattura che nessuna coppia di corpi può scambiare le loro menti più di una volta.

Sfida

Scrivi un programma o una funzione che accetta una raccolta valida di scambi mente-corpo che si sono già verificati e genera un insieme legale di scambi che riporterà ogni mente al suo corpo originale. Gli identificatori per queste raccolte corpo-mente devono essere stringhe che non conterranno nuove righe. È possibile aggiungere fino a due persone (con un nome distinto) che non hanno avuto scambi precedenti con il gruppo di input. (Prova che sono necessari solo al massimo 2 corpi aggiuntivi) Tuttavia, è necessario aggiungere il numero minimo di persone richieste per risolvere il problema.

L'input e l'output possono assumere qualsiasi forma chiara, tuttavia, nessuna informazione aggiuntiva può essere memorizzata in entrambi. Puoi presumere che sia sempre valido. Questo è il codice golf, quindi il vincitore è l'invio con il minor numero di byte.

Esempi

[('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"

Quello dello spettacolo:

[("Amy","Hubert"),("Bender","Amy"),("Hubert","Turanga"),("Amy","Wash Bucket"),("Wash Bucket","Nikolai"),("Phillip","John"),("Hermes","Turanga")]

La soluzione dello spettacolo, fornita di seguito, non è valida:

[("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")]

Questo non è valido perché Ethan e Clyde non sono necessari a causa di quanto poco Fry Phillip, Zoidberg John ed Hermes Hermes usassero la macchina. Di seguito viene fornita una soluzione valida per questo caso:

[("Philip","Hubert"),("John","Wash Bucket"),("Philip","Turanga"),("John","Nikolai"),("Philip","Hermes"),("John","Bender"),("Philip","Amy"),("John","Hubert"),("Philip","Wash Bucket")]

Si noti che ci sono chiaramente molte risposte possibili per qualsiasi input valido. Qualsiasi è valido.


Ci sono alcuni nomi che possiamo presumere non verranno utilizzati?
feersum

@feersum No, parte della sfida;)
FryAmTheEggman

1
@feersum Vuoi dire se hai preso l'intero input come stringa? Quindi sì, tuttavia, puoi presumere che i nomi non avranno nuove righe tra di loro. (modificando questo adesso)
FryAmTheEggman

1
La tua soluzione per l'input dello spettacolo non funziona. Amy e Bender vengono scambiati alla fine. Una soluzione corretta sarebbe[('Nikolai', 'Phillip'), ('Nikolai', 'Hubert'), ('Nikolai', 'Turanga'), ('Nikolai', 'Bender'), ('Phillip', 'Amy'), ('John', 'Wash Bucket'), ('Nikolai', 'John'), ('Phillip', 'Wash Bucket'), ('Hubert', 'John'), ('Bender', 'Hermes')]
Jakube,

1
@Jakube Siamo spiacenti, sembra che abbia fatto un refuso quando sono entrato nella situazione per lo spettacolo. Credo che sia stato risolto ora e la soluzione sia ok.
FryAmTheEggman,

Risposte:


3

Python 3: 328 caratteri (lento), 470 caratteri (veloce)

Probabilmente un po 'troppo a lungo per una risposta seria.

Codice lento e corto:

from itertools import*
def d(u,s):i,j=map(u.index,s);u[i],u[j]=u[j],u[i]
def f(Q):
 n=set()
 for s in Q:n|=set(s)
 n=list(n)
 while 1:
  for t in permutations(i for i in combinations(n,2)if not set((i,i[::-1]))&set(Q)):
   u=n[:];j=0
   for s in Q:d(u,s)
   for s in t:
    j+=1;d(u,s)
    if n==u:return t[:j]
  n+=[''.join(n)]

d(u,s)applica uno scambio sa u. Nel metodo principale f(Q), per prima cosa creo l'elenco di tutte le persone nusando le operazioni impostate e riconvertendo il risultato in un elenco. La while 1-loop è, naturalmente, non è un loop infinito. In esso, provo anche a risolvere il problema usando le persone che ho dentro n. Se non riesce, aggiungo un'altra persona combinando tutti i nomi n+=[''.join(n)]. Pertanto il while 1-loop viene eseguito al massimo 3 volte (vedere la prova nella domanda).

La risoluzione del problema è fatta bruteforce. Genero tutti gli swap che sono legali e provo tutte le permutazioni for t in permutations(i for i in combinations(n,2)if not set((i,i[::-1]))&set(Q)). Se ogni persona è nel proprio corpo, restituisco la sequenza di swap.

Uso:

print(f([('A','B'),('C','D')]))
print(f([('A','B')]))
print(f([('A','B'),('C','D'),('A','C'),('A','D')]))

L'esempio di futurama impiega troppo tempo. Ci sono 9 persone, quindi ci sono 36 possibili swap e 28 di loro sono legali. Quindi ci sono 26! permutazioni legali.

Codice più veloce

def w(u,s):i,j=map(u.index,s);u[i],u[j]=u[j],u[i]
def f(Q):
 n=set()
 for s in Q:n|=set(s)
 while 1:
  n=list(n);u=n[:];l=len(n)
  for s in Q:w(u,s)
  for d in range((l*l-l)//2-len(Q)+1):r(n,u,Q,[],d)
  n+=[''.join(n)]
def r(n,u,Q,t,d):
 m=0;v=u[:];l=len(u)
 for i in range(l):
  if n[i]!=v[i]:m+=1;w(v,(n[i],v[i]))
 if m<1:print(t);exit()
 for i in range(l*l):
  s=n[i//l],n[i%l]
  if m<=d and i//l<i%l and not set([s,s[::-1]])&set(Q+t):v=u[:];w(v,s);r(n,v,Q,t+[s],d-1)

La funzione f(Q)ha un approccio iterativo di approfondimento. Prima prova profondità = 0, quindi profondità = 1, fino a profondità = (l * ll) // 2-len (Q), che è il numero massimo di mosse legali. Come il codice più lento, aggiunge un'altra persona e riprova.

La funzione ricorsiva r(n,u,Q,t,d)tenta di risolvere la posizione corrente ucon dswap. nè la posizione risolta, Ql'ingresso si sposta e tgli spostamenti sono già stati eseguiti. Calcola innanzitutto un limite inferiore di swap mnecessari (risolvendo lo stato con swap legali e illegali). Se m== 0, tutte le persone sono nel corpo corretto, quindi stampa la soluzione t. Altrimenti prova tutti i possibili swap s, se m<d(potatura), d>1(che è già incluso in m<d, i//l<i%l(non consentire scambi come ('A','A')o ('A','B')e ('B','A')) e not set([s,s[::-1]])&set(Q+t)( snon è stato ancora eseguito).

Uso:

f([("Amy","Hubert"),("Bender","Amy"),("Hubert","Turanga"),("Amy","Wash Bucket"),("Wash Bucket","Nikolai"),("Philip","John"),("Hermes","Turanga")])

Trova gli swap ottimali per il problema futurama in circa 17 secondi sul mio laptop usando pypy e circa 2 minuti senza pypy. Si noti che entrambi gli algoritmi producono soluzioni diverse quando lo si chiama con lo stesso parametro. Ciò è dovuto all'algoritmo di hashing di un pitone- set. nmemorizza la persona ogni volta in un ordine diverso. Pertanto l'algoritmo può essere più veloce o più lento ad ogni corsa.

Modifica: il caso di prova futurama originale era sbagliato, il caso di prova corretto ha una soluzione ottimale di 9 anziché 10 ed è quindi più veloce. 2 secondi con pypy, 7 secondi senza.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.