Tin xấu, ai đó


10

Trong tập Futurama, tù nhân của các thành viên của nhóm phi hành đoàn hoán đổi thân xác với nhau, với lý do không một cặp thi thể nào có thể khiến tâm trí họ bị tráo đổi nhiều lần.

Thử thách

Viết một chương trình hoặc chức năng chấp nhận một bộ sưu tập hoán đổi thân tâm hợp lệ đã xảy ra và đưa ra một bộ hoán đổi hợp pháp sẽ đưa mỗi tâm trí trở lại cơ thể ban đầu. Các định danh cho các bộ sưu tập thân tâm này phải là các chuỗi sẽ không chứa các dòng mới. Bạn có thể thêm tối đa hai người (được đặt tên rõ ràng), những người không có giao dịch hoán đổi trước với nhóm đầu vào. (Bằng chứng là bạn chỉ cần tối đa 2 cơ quan bổ sung) Tuy nhiên, bạn phải thêm số người tối thiểu cần thiết để giải quyết vấn đề.

Đầu vào và đầu ra có thể có bất kỳ hình thức rõ ràng nào, tuy nhiên, không có thông tin bổ sung nào có thể được lưu trữ trong một trong hai. Bạn có thể cho rằng nó luôn hợp lệ. Đây là mã golf, vì vậy người chiến thắng là bài nộp với ít byte nhất.

Ví dụ

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

Một trong những chương trình:

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

Giải pháp của chương trình, được đưa ra dưới đây là không hợp lệ:

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

Điều này không hợp lệ vì Ethan và Clyde không cần thiết vì cách mà Fry Phillip, Zoidberg John và Hermes Hermes sử dụng máy rất ít. Một giải pháp hợp lệ cho trường hợp này được cung cấp dưới đây:

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

Lưu ý rằng rõ ràng có nhiều câu trả lời có thể cho bất kỳ đầu vào hợp lệ. Bất kỳ là hợp lệ.


Có một số tên chúng ta có thể giả sử sẽ không được sử dụng?
frageum

@feersum Không, một phần của thử thách;)
FryAmTheEggman

1
@feersum Ý bạn là nếu bạn lấy toàn bộ đầu vào dưới dạng một chuỗi? Sau đó, có, tuy nhiên, bạn có thể giả sử tên sẽ không có dòng mới giữa chúng. (chỉnh sửa ngay bây giờ)
FryAmTheEggman

1
Giải pháp của bạn cho đầu vào của chương trình không hoạt động. Amy và Bender được hoán đổi ở cuối. Một giải pháp chính xác sẽ là[('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 Xin lỗi, có vẻ như tôi đã mắc lỗi đánh máy khi tham gia vào tình huống cho chương trình. Tôi tin rằng nó đã được sửa bây giờ, và giải pháp là ok.
FryAmTheEggman

Câu trả lời:


3

Python 3: 328 ký tự (chậm), 470 ký tự (nhanh)

Có lẽ là một chút quá dài cho một câu trả lời nghiêm túc.

Mã chậm và ngắn:

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)áp dụng một trao đổi sđể u. Trong phương thức chính f(Q), trước tiên tôi tạo danh sách tất cả những người nsử dụng các thao tác đã đặt và chuyển đổi kết quả trở lại danh sách. Các while 1-loop tất nhiên không phải là một vòng lặp vô cực. Trong đó, tôi cũng cố gắng giải quyết vấn đề bằng cách sử dụng những người tôi có n. Nếu nó không thành công, tôi thêm một người khác bằng cách kết hợp tất cả các tên n+=[''.join(n)]. Do đó, while 1-loop được thực thi tối đa 3 lần (xem bằng chứng trong câu hỏi).

Việc giải quyết vấn đề được thực hiện bruteforce. Tôi tạo ra tất cả các giao dịch hoán đổi là hợp pháp và thử tất cả các hoán vị for t in permutations(i for i in combinations(n,2)if not set((i,i[::-1]))&set(Q)). Nếu mỗi người ở trong cơ thể của chính nó, tôi sẽ trả lại chuỗi hoán đổi.

Sử dụng:

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

Ví dụ từ Futurama mất quá nhiều thời gian. Có 9 người, vì vậy có 36 giao dịch hoán đổi có thể và 28 người trong số họ là hợp pháp. Vậy là có 26! hoán vị pháp lý.

Mã nhanh hơn

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)

Các chức năng f(Q)có một cách tiếp cận sâu lặp đi lặp lại. Đầu tiên, nó thử độ sâu = 0, sau đó độ sâu = 1, cho đến độ sâu = (l * ll) // 2-len (Q), đây là số lần di chuyển hợp pháp tối đa. Giống như mã chậm hơn, sau đó thêm một người khác và thử lại.

Hàm đệ quy r(n,u,Q,t,d)cố gắng giải quyết vị trí hiện tại ubằng các dgiao dịch hoán đổi. nlà vị trí đã giải quyết, Qdi chuyển đầu vào và tdi chuyển đã được thực hiện. Đầu tiên, nó tính toán giới hạn dưới của các giao dịch hoán đổi mcần thiết (bằng cách giải quyết trạng thái bằng các giao dịch hoán đổi hợp pháp và bất hợp pháp). Nếu m== 0, tất cả mọi người đều ở trong thân chính xác, vì vậy nó sẽ in ra giải pháp t. Nếu không nó sẽ cố gắng tất cả các giao dịch hoán đổi có thể s, nếu m<d(cắt tỉa), d>1(mà đã được bao gồm trong m<d, i//l<i%l(tôi không cho phép hoán đổi như ('A','A')hay ('A','B')('B','A')) và not set([s,s[::-1]])&set(Q+t)( schưa được thực hiện chưa).

Sử dụng:

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

Nó tìm thấy các giao dịch hoán đổi tối ưu cho vấn đề Futurama trong khoảng 17 giây trên máy tính xách tay của tôi bằng cách sử dụng pypy và khoảng 2 phút mà không có pypy. Lưu ý rằng cả hai thuật toán đều đưa ra các giải pháp khác nhau, khi gọi nó với cùng một tham số. Điều này là do thuật toán băm của một con trăn- set. nlưu trữ người mỗi lần theo một thứ tự khác nhau. Do đó, thuật toán có thể nhanh hơn hoặc chậm hơn mỗi lần chạy.

Chỉnh sửa: Trường hợp thử nghiệm Futurama ban đầu đã sai, trường hợp thử nghiệm được sửa có giải pháp tối ưu là 9 thay vì 10, và do đó nhanh hơn. 2 giây với pypy, 7 giây không có.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.