나쁜 소식, 누군가


10

Futurama 에피소드 에서 승무원 의 Benda의 죄수는 서로 몸을 교환하고, 한 쌍의 몸도 마음을 두 번 이상 교환 할 수 없다는 캐치를 사용합니다 .

도전

이미 발생한 유효한 마인드 바디 스왑 모음을 허용하고 각 마인드를 원래 바디에 반환하는 합법적 인 스왑 세트를 출력하는 프로그램 또는 함수를 작성하십시오. 이러한 마인드 바디 컬렉션의 식별자는 개행 문자를 포함하지 않는 문자열이어야합니다. 입력 그룹과의 이전 스왑이없는 최대 2 명 (명명하게)을 추가 할 수 있습니다. (최대 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")]

Fry Phillip, Zoidberg John 및 Hermes Hermes가 기계 를 얼마나 적게 사용했기 때문에 Ethan과 Clyde가 필요하지 않기 때문에 이것은 유효하지 않습니다 . 이 경우에 유효한 솔루션은 다음과 같습니다.

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

파이썬 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)에서는 먼저 nset 작업을 사용하여 모든 사람의 목록을 생성 하고 결과를 다시 목록으로 변환합니다. 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')]))

futurama의 예는 너무 오래 걸립니다. 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)에는 반복 심화 접근 방식이 있습니다. 깊이 = (l * ll) // 2-len (Q)까지 최대 = 0, 그 다음 깊이 = 1을 시도합니다. 이는 최대 법적 이동 수입니다. 느린 코드처럼 다른 사람을 추가하고 다시 시도합니다.

재귀 함수는 r(n,u,Q,t,d)현재 위치 해결하려고 ud스왑. 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")])

그것은 pypy를 사용하여 랩톱에서 약 17 초 안에 pypy없이 약 2 분 안에 futurama 문제에 대한 최적의 스왑을 찾습니다. 동일한 매개 변수로 호출 할 때 두 알고리즘 모두 서로 다른 솔루션을 출력합니다. 이것은 파이썬의 해싱 알고리즘 때문입니다 set. n매번 다른 순서로 사람을 저장합니다. 따라서 알고리즘이 실행될 때마다 빠르거나 느려질 수 있습니다.

편집 : 원래 futurama 테스트 사례가 잘못되었고 수정 된 테스트 사례는 10 대신 9의 최적 솔루션을 가지므로 더 빠릅니다. 파이와 함께 2 초,없이 7 초.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.