Berita Buruk, Seseorang

10

Dalam episode Futurama, Tahanan Benda anggota kru bertukar tubuh satu sama lain, dengan tangkapan bahwa tidak ada pasangan tubuh yang dapat bertukar pikiran lebih dari satu kali.

Tantangan

Tulis sebuah program atau fungsi yang menerima kumpulan swap pikiran-tubuh yang sah yang telah terjadi, dan mengeluarkan serangkaian pertukaran hukum yang akan mengembalikan setiap pikiran ke tubuh aslinya. Pengidentifikasi untuk koleksi pikiran-tubuh ini harus berupa string yang tidak akan berisi baris baru. Anda dapat menambahkan hingga dua orang (yang diberi nama berbeda) yang belum pernah berganti ke grup input. (Bukti bahwa Anda hanya membutuhkan paling banyak 2 badan tambahan) Namun, Anda harus menambahkan jumlah minimum orang yang diperlukan untuk menyelesaikan masalah.

Input dan output dapat mengambil bentuk yang jelas, namun tidak ada informasi tambahan yang dapat disimpan. Anda mungkin menganggap itu selalu valid. Ini adalah kode golf, jadi pemenangnya adalah pengiriman dengan byte paling sedikit.

Contohnya

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

Yang dari acara:

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

Solusi acara, yang diberikan di bawah ini tidak valid:

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

Ini tidak valid karena Ethan, dan Clyde tidak perlu karena seberapa sedikit Fry Phillip, Zoidberg John dan Hermes Hermes menggunakan mesin. Solusi yang valid untuk kasus ini disediakan di bawah ini:

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

Perhatikan bahwa ada banyak kemungkinan jawaban untuk setiap input yang valid. Apa pun valid.

FryAmTheEggman
sumber
Adakah beberapa nama yang dapat kita asumsikan tidak akan digunakan?
feersum
@feersum Tidak, bagian dari tantangan;)
FryAmTheEggman
1
@feersum Maksud Anda jika Anda mengambil seluruh input sebagai string? Maka ya, bagaimanapun, Anda dapat menganggap nama tidak akan memiliki baris baru di antara mereka. (mengedit ini sekarang)
FryAmTheEggman
1
Solusi Anda untuk input acara tidak berfungsi. Amy dan Bender ditukar pada akhirnya. Solusi yang tepat adalah[('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 Maaf, sepertinya saya membuat kesalahan ketik ketika memasuki situasi untuk pertunjukan. Saya percaya itu sudah diperbaiki sekarang, dan solusinya ok.
FryAmTheEggman

Jawaban:

3

Python 3: 328 karakter (lambat), 470 karakter (cepat)

Mungkin agak terlalu lama untuk jawaban yang serius.

Kode lambat dan pendek:

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)berlaku swap ske u. Dalam metode utama f(Q), saya pertama-tama menghasilkan daftar semua orang nmenggunakan operasi yang ditetapkan dan mengubah hasilnya kembali ke daftar. The while 1-loop tentu saja tidak loop tak terbatas. Di dalamnya, saya mencoba juga memecahkan masalah menggunakan orang yang saya miliki n. Jika tidak berhasil, saya menambahkan orang lain dengan menggabungkan semua nama n+=[''.join(n)]. Oleh karena itu while 1-loop dieksekusi paling banyak 3 kali (lihat bukti dalam pertanyaan).

Pemecahan masalah dilakukan bruteforce. Saya menghasilkan semua swap yang legal dan mencoba semua permutasi for t in permutations(i for i in combinations(n,2)if not set((i,i[::-1]))&set(Q)). Jika setiap orang berada di dalam tubuhnya sendiri, saya mengembalikan urutan swap.

Pemakaian:

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

Contoh dari futurama terlalu lama. Ada 9 orang, jadi ada 36 kemungkinan swap dan 28 di antaranya legal. Jadi ada 26! permutasi hukum.

Kode lebih cepat

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)

Fungsi ini f(Q)memiliki pendekatan pendalaman berulang. Pertama mencoba kedalaman = 0, kemudian kedalaman = 1, sampai kedalaman = (l * ll) // 2-len (Q), yang merupakan jumlah maksimum dari langkah hukum. Seperti kode yang lebih lambat, ia kemudian menambahkan orang lain dan mencoba lagi.

Fungsi rekursif r(n,u,Q,t,d)mencoba untuk menyelesaikan posisi saat ini udengan dswap. nadalah posisi yang dipecahkan, Qinput bergerak dan tbergerak sudah dilakukan. Pertama-tama ia menghitung batas bawah swap yang mdiperlukan (dengan menyelesaikan negara dengan swap legal dan ilegal). Jika m== 0, semua orang berada di badan yang benar, sehingga ia mencetak solusinya t. Kalau tidak, ia mencoba semua kemungkinan swap s, jika m<d(pemangkasan), d>1(yang sudah termasuk dalam m<d, i//l<i%l(jangan izinkan swap seperti ('A','A')atau ('A','B')dan ('B','A')) dan not set([s,s[::-1]])&set(Q+t)( sbelum dilakukan).

Pemakaian:

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

Ia menemukan swap optimal untuk masalah futurama dalam waktu sekitar 17 detik pada laptop saya menggunakan pypy dan sekitar 2 menit tanpa pypy. Perhatikan bahwa kedua algoritma menghasilkan solusi yang berbeda, saat memanggilnya dengan parameter yang sama. Ini karena algoritma hashing dari python- set. nmenyimpan orang tersebut setiap kali dalam urutan yang berbeda. Oleh karena itu algoritme mungkin lebih cepat atau lebih lambat setiap kali dijalankan.

Sunting: Kasing uji futurama asli salah, kasing yang dikoreksi memiliki solusi optimal 9 bukannya 10, dan karenanya lebih cepat. 2 detik dengan pypy, 7 detik tanpa.

Jakube
sumber