Погані новини, хтось


10

У епізоді " Футурама " члени екіпажу "В'язень Бенди " обмінюються тілами один з одним, із тим, що жодна пара тіл не може змінювати розум не один раз.

Виклик

Напишіть програму або функцію, яка приймає дійсну колекцію змін, що вже відбулися, і виводить законний набір свопів, які повертають кожен розум до його початкового тіла. Ідентифікатори цих колекцій душевного тіла повинні бути рядками, які не містять нових рядків. Ви можете додати до двох (чітко названих) людей, які не мали попередніх свопів до групи вводу. (Доказ того, що вам потрібно лише щонайменше 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")]

Це недійсно, тому що Етан та Клайд непотрібні через те, як мало Фрі Філліп, Джон Зойдберг та Гермес Гермес використовували машину. Дійсне рішення для цього випадку подано нижче:

[("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')]
Якубе

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

Він знайде оптимальні заміни для проблеми з футурамою приблизно за 17 секунд на моєму ноутбуці за допомогою pypy і приблизно за 2 хвилини без pypy. Зауважте, що обидва алгоритми виводять різні рішення, коли викликають його з одним і тим же параметром. Це пояснюється алгоритмом хешування пітона set. nзберігає людину кожного разу в іншому порядку. Тому алгоритм може бути швидшим або повільнішим кожного запуску.

Редагувати: Оригінальний тест футурами був помилковим, виправлений тестовий випадок має оптимальне рішення 9 замість 10, а тому швидше. 2 секунди з pypy, 7 секунд без.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.