Schlechte Nachrichten, jemand

10

In der Folge Futurama Der Gefangene von Benda Mitglieder der Besatzung Wechselbrücken miteinander, mit dem Fang , dass kein Paar von Körpern ihren Köpfen haben können getauscht mehr als einmal.

Herausforderung

Schreiben Sie ein Programm oder eine Funktion, die eine gültige Sammlung bereits aufgetretener Mind-Body-Swaps akzeptiert und eine legale Reihe von Swaps ausgibt, die jeden Mind zu seinem ursprünglichen Körper zurückführen. Die Bezeichner für diese Mind-Body-Sammlungen müssen Zeichenfolgen sein, die keine Zeilenumbrüche enthalten. Sie können der Eingabegruppe bis zu zwei (eindeutig benannte) Personen hinzufügen, die zuvor keine Auslagerungen vorgenommen haben. (Nachweis, dass Sie höchstens 2 zusätzliche Stellen benötigen) Sie müssen jedoch die Mindestanzahl von Personen hinzufügen, die zur Lösung des Problems erforderlich sind.

Die Eingabe und Ausgabe kann eine eindeutige Form annehmen, es können jedoch auch keine zusätzlichen Informationen gespeichert werden. Sie können davon ausgehen, dass es immer gültig ist. Dies ist Code Golf, der Gewinner ist also die Einreichung mit den wenigsten Bytes.

Beispiele

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

Der aus der Show:

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

Die unten angegebene Lösung der Show ist ungültig:

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

Dies ist ungültig, da Ethan und Clyde unnötig sind, da Fry Phillip, Zoidberg John und Hermes Hermes die Maschine nur wenig benutzt haben. Eine gültige Lösung für diesen Fall finden Sie unten:

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

Beachten Sie, dass es für jede gültige Eingabe eindeutig viele mögliche Antworten gibt. Jeder ist gültig.

FryAmTheEggman
quelle
Gibt es einige Namen, von denen wir annehmen können, dass sie nicht verwendet werden?
Feersum
@feersum Nein, Teil der Herausforderung;)
FryAmTheEggman
1
@feersum Du meinst, wenn du die gesamte Eingabe als String genommen hast? Dann können Sie jedoch davon ausgehen, dass zwischen Namen keine Zeilenumbrüche stehen. (Bearbeiten Sie dies jetzt)
FryAmTheEggman
1
Ihre Lösung für die Eingabe der Show funktioniert nicht. Amy und Bender werden am Ende getauscht. Eine richtige Lösung wäre[('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 Sorry, es scheint, dass ich einen Tippfehler gemacht habe, als ich in die Situation für die Show eingetreten bin. Ich glaube, es ist jetzt behoben und die Lösung ist in Ordnung.
FryAmTheEggman

Antworten:

3

Python 3: 328 Zeichen (langsam), 470 Zeichen (schnell)

Wahrscheinlich etwas zu lang für eine ernsthafte Antwort.

Langsamer und kurzer Code:

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)wendet einen Tausch san u. Bei der Hauptmethode f(Q)generiere ich zuerst die Liste aller Personen nmit festgelegten Operationen und konvertiere das Ergebnis zurück in eine Liste. Die while 1-schleife ist natürlich keine Endlosschleife. Darin versuche ich auch, das Problem mit den Personen zu lösen, in denen ich mich befinde n. Wenn es nicht erfolgreich ist, füge ich eine weitere Person hinzu, indem ich alle Namen kombiniere n+=[''.join(n)]. Daher wird die while 1-schleife höchstens dreimal ausgeführt (siehe Beweis in der Frage).

Die Lösung des Problems erfolgt mit Bruteforce. Ich generiere alle Swaps, die legal sind und versuche alle Permutationen for t in permutations(i for i in combinations(n,2)if not set((i,i[::-1]))&set(Q)). Wenn sich jede Person in ihrem eigenen Körper befindet, gebe ich die Reihenfolge der Swaps zurück.

Verwendungszweck:

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

Das Beispiel aus Futurama dauert viel zu lange. Es gibt 9 Personen, also gibt es 36 mögliche Swaps und 28 davon sind legal. Es gibt also 26! rechtliche Permutationen.

Schnellerer Code

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)

Die Funktion verfolgt f(Q)einen iterativen Vertiefungsansatz. Zuerst wird Tiefe = 0, dann Tiefe = 1 versucht, bis Tiefe = (l * ll) // 2-len (Q), was die maximale Anzahl legaler Züge ist. Wie der langsamere Code fügt er dann eine weitere Person hinzu und versucht es erneut.

Die rekursive Funktion r(n,u,Q,t,d)versucht, die aktuelle Position umit dSwaps zu lösen . nIst die gelöste Position, Qbewegt sich die Eingabe und tdie Bewegungen bereits ausgeführt. Zunächst wird eine Untergrenze der mbenötigten Swaps berechnet (indem der Staat mit legalen und illegalen Swaps gelöst wird). Wenn m== 0, befinden sich alle Personen im richtigen Körper, sodass die Lösung gedruckt wird t. Andernfalls werden alle möglichen Swaps versucht s, wenn m<d(Bereinigen) d>1(was bereits in enthalten m<dist i//l<i%l(Swaps wie ('A','A')oder ('A','B')und nicht zulassen ('B','A')) und not set([s,s[::-1]])&set(Q+t)( snoch nicht durchgeführt wurde).

Verwendungszweck:

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

Es findet die optimalen Swaps für das Futurama-Problem in ungefähr 17 Sekunden auf meinem Laptop mit Pypy und ungefähr 2 Minuten ohne Pypy. Beachten Sie, dass beide Algorithmen unterschiedliche Lösungen ausgeben, wenn sie mit demselben Parameter aufgerufen werden. Dies liegt am Hashing-Algorithmus eines Python- set. nspeichert die Person jedes Mal in einer anderen Reihenfolge. Daher kann der Algorithmus bei jedem Lauf schneller oder langsamer sein.

Bearbeiten: Der ursprüngliche Futurama-Testfall war falsch, der korrigierte Testfall hat eine optimale Lösung von 9 statt 10 und ist daher schneller. 2 Sekunden mit Pypy, 7 Sekunden ohne.

Jakube
quelle