주어진 숫자 목록과 산술 연산자를 사용하여 숫자 생성


11

당신은 숫자의 목록 L = [17, 5, 9, 17, 59, 14], 운영자 가방 O = {+:7, -:3, *:5, /:1}과 숫자가 제공 N = 569됩니다.

직무

L왼쪽의 모든 숫자 와 N오른쪽 의 숫자 만 사용하는 방정식을 출력합니다 . 이것이 가능하지 않으면 False를 출력하십시오. 솔루션 예 :

59*(17-5)-9*17+14 = 569

한계와 설명

  • 숫자를 연결할 [13,37]수 없습니다 (로 사용할 수 없음 1337)
  • 에 자연수와 0 만 나타납니다 L.
  • 순서는 L중요하지 않습니다.
  • 의 모든 숫자를 사용해야합니다 L.
  • 만 연산자는 +, -, *, /에 나타납니다 O.
  • O필요한 것보다 많은 연산자를 가질 수 있지만 최소한 |L|-1연산자는
  • 의 값까지 각 연산자를 여러 번 사용할 수 있습니다 O.
  • 네 가지 연산 모두 O표준 수학 연산입니다. 특히 /정확한 분수를 갖는 정규 분할입니다.

포인트들

  • 적은 점수, 더 나은
  • 코드의 모든 문자는 하나의 포인트를 제공합니다

읽기 쉬운 골프 용 버전을 제공해야합니다.

배경

비슷한 질문은 스택 오버플로에 질문을 받았다. 흥미로운 코드 골프 과제라고 생각했습니다.

계산 복잡성

Peter Taylor가 의견에서 말했듯 이 다음과 같이 부분 집합 합계 를 해결할 수 있습니다 .

  1. 부분 집합 합계의 인스턴스가 있습니다 (따라서 정수 세트 S와 숫자 x)
  2. L : = S + [0, ..., 0] (| S | 곱하기 0), N : = x, O : = {+ : | S | -1, * : | S | -1, / : 0,-: 0}
  3. 이제 내 문제 의이 사례를 해결하십시오.
  4. 부분 집합 합계에 대한 솔루션은 0으로 곱하지 않은 S의 수입니다.

O (2 ^ n)보다 나은 알고리즘을 찾으면 P = NP임을 증명합니다. 으로 NP 대 P가 A는 밀레니엄 상 문제 때문에 가치가 100 만 미국 달러, 누군가가 이것에 대한 해결책을 발견하는 것이 매우 어렵다. 그래서 나는 순위의이 부분을 제거했습니다.

테스트 사례

다음은 유일하게 유효한 답변이 아니며 다른 솔루션이 있으며 허용됩니다.

  • ( [17,5,9,17,59,14], {+:7, -:3, *:5, /:1}, 569)
    => 59 * (17-5)- 9 * 17 + 14 = 569
  • ( [2,2], {'+':3, '-':3, '*':3, '/':3}, 1)
    => 2/2 = 1
  • ( [2,3,5,7,10,0,0,0,0,0,0,0], {'+':20, '-':20, '*':20, '/':20}, 16)
    => 5+10-2*3+7+0+0+0+0+0+0+0 = 16
  • ( [2,3,5,7,10,0,0,0,0,0,0,0], {'+':20, '-':20, '*':20, '/':20}, 15)
    => 5+10+0*(2+3+7)+0+0+0+0+0+0 = 15

입니까 m = |L|? 그렇다면 어떻게 런타임이 해당 목록의 크기에 의존하지 않을 것으로 예상 할 수 있습니까? 예를 들면 다음과 같습니다 [2,2],[+,+,...,+,/],1. 사실, n은 O (m)이므로 m으로 만 쓸 수 있습니다.
boothby

3
정확한 분수, 정수 ( /div), 부동 소수점, 반올림 할 수없는 오류 등 어떤 종류의 산술이 사용 됩니까?
반 시계 회전을 중단

4
계산 복잡성에 대해 복잡한 스코어링 규칙이 필요한 이유는 무엇입니까? 부분 집합 합계를 쉽게 줄일 수 있으므로 O (2 ^ n)보다 나은 것은 백만 달러의 가치가 있습니다.
피터 테일러


1
세 번째 테스트 사례는 거짓이 아닙니다 ...5+10+2*3+7*0+0...
Shmiddty

답변:


3

파이썬 2.7 / 478 자

L=[17,5,9,17,59,14]
O={'+':7,'-':3,'*':5,'/':1}
N=569
P=eval("{'+l+y,'-l-y,'*l*y,'/l/y}".replace('l',"':lambda x,y:x"))
def S(R,T):
 if len(T)>1:
  c,d=y=T.pop();a,b=x=T.pop()
  for o in O:
   if O[o]>0 and(o!='/'or y[0]):
    T+=[(P[o](a, c),'('+b+o+d+')')];O[o]-=1
    if S(R,T):return 1
    O[o]+=1;T.pop()
  T+=[x,y]
 elif not R:
  v,r=T[0]
  if v==N:print r
  return v==N
 for x in R[:]:
  R.remove(x);T+=[x]
  if S(R,T):return 1
  T.pop();R+=[x]
S([(x,`x`)for x in L],[])

주요 아이디어는 접미사 형식의 표현식을 사용하여 검색하는 것입니다. 예를 들어 2*(3+4)접미사 형식은입니다 234+*. 따라서 문제는에 L+ 의 부분 순열을 찾는 것이 O됩니다 N.

다음 버전은 ungolfed 버전입니다. 스택 stk은 다음과 같습니다 [(5, '5'), (2, '5-3', (10, ((4+2)+(2*(4/2))))].

L = [17, 5, 9, 17, 59, 14]
O = {'+':7, '-':3, '*':5, '/':1} 
N = 569

P = {'+':lambda x,y:x+y,
     '-':lambda x,y:x-y,
     '*':lambda x,y:x*y,
     '/':lambda x,y:x/y}

def postfix_search(rest, stk):
    if len(stk) >= 2:
        y = (v2, r2) = stk.pop()
        x = (v1, r1) = stk.pop()
        for opr in O:
            if O[opr] > 0 and not (opr == '/' and v2 == 0):
                stk += [(P[opr](v1, v2), '('+r1+opr+r2+')')]
                O[opr] -= 1
                if postfix_search(rest, stk): return 1
                O[opr] += 1
                stk.pop()
        stk += [x, y]
    elif not rest:
        v, r = stk[0]
        if v == N: print(r)
        return v == N
    for x in list(rest):
        rest.remove(x)
        stk += [x]
        if postfix_search(rest, stk):
            return True
        stk.pop()
        rest += [x]
postfix_search(list(zip(L, map(str, L))), [])

1
와우, 그것은 내가 예상했던 것보다 짧다. 변환 postfix <=> infix가 포함 된 알고리즘을 낙서했지만 내 낙서는 구현보다 훨씬 짧지 않았습니다. 감동. 그리고 건축 주셔서 감사합니다 P[opr](v1, v2). 지금은 분명해 보이지만 람다와 사전을 이와 같이 결합시키는 것에 대해서는 결코 생각하지 않았습니다.
마틴 토마

4 번째 테스트 케이스로 솔루션을 테스트하려고했습니다. 2 시간 후, 나는 사형 집행을 중단했다.
Martin Thoma

@moose 나는 좀 더 빠른 휴리스틱을 추가하려고 노력할 것이다. 그러나 그 후 코드 길이는 두 배가 될 수 있습니다.
Ray

여기에서 와 같이 분수를 사용하면 답변의 문제가 해결됩니다. 제공된 링크에서 주어진 인스턴스에 대해 시도하십시오. 현재 코드는 답을 찾지 못하지만 분수를 사용할 때 대답을 찾습니다.
Martin Thoma
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.