ข่าวร้ายมีคน


10

ในตอนทุรานักโทษแห่ง Bendaสมาชิกของร่างกายแลกเปลี่ยนลูกเรือกับแต่ละอื่น ๆ ด้วยการจับคู่ที่ไม่ร่างกายสามารถมีจิตใจของพวกเขาสลับมากกว่าหนึ่งครั้ง

ท้าทาย

เขียนโปรแกรมหรือฟังก์ชั่นที่ยอมรับคอลเลกชั่นสว็อป - จิตใจที่ถูกต้องที่เกิดขึ้นแล้วและส่งชุดสว็อปตามกฎหมายที่จะนำจิตใจแต่ละดวงกลับคืนสู่ร่างกายดั้งเดิม ตัวระบุสำหรับคอลเลกชันของร่างกายและจิตใจเหล่านี้จะต้องเป็นสตริงซึ่งจะไม่ขึ้นบรรทัดใหม่ คุณสามารถเพิ่มผู้คนที่ไม่เคยมีการสลับไปยังกลุ่มอินพุทได้ถึงสองคน (ตั้งชื่ออย่างชัดเจน) (พิสูจน์ได้ว่าคุณต้องการร่างกายเพิ่มได้เพียง 2 ตัวเท่านั้น)อย่างไรก็ตามคุณต้องเพิ่มจำนวนคนขั้นต่ำที่จำเป็นในการแก้ปัญหา

การป้อนข้อมูลและการส่งออกอาจมีรูปแบบที่ชัดเจนใด ๆ แต่ไม่มีข้อมูลเพิ่มเติมสามารถเก็บไว้ในทั้ง คุณอาจคิดว่ามันถูกต้องเสมอ นี่คือรหัสกอล์ฟดังนั้นผู้ชนะคือการส่งที่มีไบต์น้อยที่สุด

ตัวอย่าง

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

หนึ่งจากการแสดง:

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

วิธีแก้ปัญหาของรายการที่ระบุด้านล่างไม่ถูกต้อง:

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

สิ่งนี้ไม่ถูกต้องเนื่องจากอีธานและไคลด์ไม่จำเป็นเพราะฟิลลิปฟรายเล็กน้อย, Zoidberg John และHermes Hermes ใช้เครื่อง วิธีแก้ปัญหาที่ถูกต้องสำหรับกรณีนี้มีให้ด้านล่าง:

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

โปรดทราบว่ามีคำตอบที่เป็นไปได้อย่างชัดเจนสำหรับอินพุตที่ถูกต้อง ใด ๆ ที่ถูกต้อง


มีชื่อบางอย่างที่เราสามารถสันนิษฐานได้ว่าจะไม่ถูกใช้?
feersum

@feersum Nope ส่วนหนึ่งของความท้าทาย;)
FryAmTheEggman

1
@feersum คุณหมายถึงถ้าคุณใส่ข้อมูลทั้งหมดเป็นสตริง? อย่างไรก็ตามใช่คุณสามารถสันนิษฐานได้ว่าชื่อจะไม่มีการขึ้นบรรทัดใหม่ระหว่างกัน (แก้ไขในตอนนี้)
FryAmTheEggman

1
โซลูชันของคุณสำหรับอินพุตของรายการไม่ทำงาน เอมีและเบนเดอร์ถูกสับเปลี่ยนในตอนท้าย ทางออกที่ถูกต้องคือ[('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 ขออภัยดูเหมือนว่าฉันจะพิมพ์ผิดเมื่อเข้าสู่สถานการณ์สำหรับการแสดง ฉันเชื่อว่ามันได้รับการแก้ไขแล้วและการแก้ปัญหาก็โอเค
FryAmTheEggman

คำตอบ:


3

Python 3: 328 อักขระ (ช้า), 470 อักขระ (เร็ว)

อาจจะนานไปหน่อยสำหรับคำตอบที่จริงจัง

รหัสช้าและสั้น:

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)ใช้สลับไปs uในวิธีการหลักf(Q)ฉันจะสร้างรายชื่อของทุกคนnโดยใช้การตั้งค่าและการแปลงผลลัพธ์กลับไปเป็นรายการ while 1-loop เป็นหลักสูตรที่ไม่ได้เป็นวงอินฟินิตี้ nในนั้นฉันพยายามแก้ปัญหาโดยใช้บุคคลที่ฉันมีในเกินไป n+=[''.join(n)]ถ้ามันไม่ประสบความสำเร็จฉันจะเพิ่มบุคคลอื่นโดยการรวมชื่อทั้งหมด ดังนั้นwhile 1-loop จะถูกดำเนินการมากที่สุด 3 ครั้ง (ดูข้อพิสูจน์ในคำถาม)

การแก้ปัญหานั้นเกิดขึ้นอย่างดุเดือด for t in permutations(i for i in combinations(n,2)if not set((i,i[::-1]))&set(Q))ฉันสร้างสัญญาทั้งหมดที่ถูกต้องตามกฎหมายและพยายามพีชคณิตทั้งหมด หากแต่ละคนอยู่ในร่างกายของตัวเองฉันจะกลับลำดับของการแลกเปลี่ยน

การใช้งาน:

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

ตัวอย่างจากทุรารายละเอียดใช้เวลานานเกินไป มี 9 คนดังนั้นจึงมี 36 สัญญาแลกเปลี่ยนที่เป็นไปได้และ 28 รายในนั้นถูกกฎหมาย ดังนั้นจึงมี 26! การเปลี่ยนแปลงทางกฎหมาย

รหัสได้เร็วขึ้น

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)

ฟังก์ชั่นf(Q)นี้มีวิธีการทำให้ลึกลงซ้ำ ก่อนอื่นให้ลองความลึก = 0 จากนั้นความลึก = 1 จนกระทั่งความลึก = (l * ll) // 2-len (Q) ซึ่งเป็นจำนวนสูงสุดของการเคลื่อนไหวทางกฎหมาย เช่นเดียวกับรหัสที่ช้าลงมันจะเพิ่มบุคคลอื่นแล้วลองอีกครั้ง

ฟังก์ชั่นวนซ้ำr(n,u,Q,t,d)พยายามที่จะแก้ปัญหาตำแหน่งปัจจุบันuด้วยการdแลกเปลี่ยน nคือตำแหน่งที่ถูกแก้ไขQอินพุตย้ายและtการย้ายที่ทำไปแล้ว ก่อนอื่นจะคำนวณขอบเขตล่างของการแลกเปลี่ยนที่mจำเป็น (โดยการแก้ไขสถานะด้วยการแลกเปลี่ยนทางกฎหมายและผิดกฎหมาย) หากm== 0, tทุกคนที่อยู่ในร่างกายที่ถูกต้องเพื่อให้มันพิมพ์การแก้ปัญหา มิฉะนั้นจะพยายามแลกเปลี่ยนเป็นไปได้ทั้งหมดsถ้าm<d(การตัดแต่งกิ่ง) d>1(ซึ่งรวมอยู่ในm<d, i//l<i%l(ไม่อนุญาตให้มีการแลกเปลี่ยนเช่น('A','A')หรือ('A','B')และ('B','A')) และnot set([s,s[::-1]])&set(Q+t)( sยังไม่ได้รับการดำเนินการยัง)

การใช้งาน:

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

พบ swaps ที่ดีที่สุดสำหรับปัญหา futurama ในเวลาประมาณ 17 วินาทีบนแล็ปท็อปของฉันโดยใช้ pypy และประมาณ 2 นาทีโดยไม่ต้อง pypy โปรดสังเกตว่าอัลกอริทึมทั้งสองแสดงผลลัพธ์ที่แตกต่างกันเมื่อเรียกใช้ด้วยพารามิเตอร์เดียวกัน เพราะนี่คือขั้นตอนวิธีการแปลงแป้นพิมพ์ของ setpython- nเก็บบุคคลในแต่ละครั้งในลำดับที่แตกต่างกัน ดังนั้นอัลกอริทึมอาจเร็วหรือช้ากว่าการรันแต่ละครั้ง

แก้ไข: กรณีทดสอบ futurama ดั้งเดิมไม่ถูกต้องกรณีทดสอบที่แก้ไขแล้วมีวิธีแก้ปัญหาที่เหมาะสมที่สุดคือ 9 แทนที่จะเป็น 10 และเร็วกว่า 2 วินาทีกับ pypy โดยไม่ต้อง 7 วินาที

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.