스틱 스택 번호


22

StickStack은 매우 간단한 스택 기반 프로그래밍 언어로 두 가지 명령 만 있습니다.

  • | 스택의 길이를 스택으로 푸시
  • -스택에서 맨 위 두 요소를 튀어 나와 그 차이를 되돌립니다 ( second topmost - topmost)

언어 세부 사항

  • 프로그램 시작시 스택이 비어 있습니다.
  • 모든 명령어는 왼쪽에서 오른쪽으로 순차적으로 실행됩니다.
  • 스택에 2 개 미만의 숫자가 있으면이 -명령은 잘못된 것입니다.
  • 실행이 끝나면 스택에는 정확히 하나의 숫자 가 포함되어야합니다 .

모든 정수는 StickStack 프로그램에 의해 생성 될 수 있습니다. 예를 들면 다음과 같습니다.

|||--||-- generates the number 2 through the following stack states:

[]
[0]
[0, 1]
[0, 1, 2]
[0, -1]
[1]
[1, 1]
[1, 1, 2]
[1, -1]
[2]    

StickStack 코드를 평가하려면 이 온라인 (CJam) 평가기를 사용할 수 있습니다 . (코드는 @Martin에게 감사합니다.)

작업

정수를 입력 출력으로 제공하는 프로그램 또는 함수를 작성하거나 주어진 수를 출력하는 StickStack 프로그램을 나타내는 문자열을 리턴해야합니다.

채점

  • 기본 점수는 아래 주어진 테스트 사례에 대한 StickStack 프로그램총 길이입니다 . 낮은 점수가 좋습니다.
  • 제출 한 내용은 모든 테스트 사례에서 프로그램을 실행하고 점수를 세는 경우에만 유효합니다.
  • 2 차 (tiebreaker) 점수는 생성 프로그램 또는 함수의 길이입니다.

입력 테스트 사례

(각 번호는 다른 테스트 사례입니다.)

-8607 -6615 -6439 -4596 -4195 -1285 -72 12 254 1331 3366 3956 5075 5518 5971 7184 7639 8630 9201 9730

프로그램은 주어진 테스트 사례뿐만 아니라 모든 정수 (데이터 유형이 처리 할 수있는)에 대해 작동해야합니다. 테스트 번호에 대한 솔루션을 프로그램에 하드 코딩해서는 안됩니다. 하드 코딩이 의심 될 경우 테스트 번호가 변경됩니다.


무차별 대입을 막기 위해 "적절한 시간에 실행"이라는 문구를 추가하는 것이 좋습니다.

@Reticality는 "모든 테스트 사례에서 프로그램을 실행 한 경우에만 유효합니다"
edc65에서

답변:


7

파이썬 2-5188

시간이 상당히 효율적이며 (아마도) 최적의 솔루션 인 것 같습니다. 나는 같은 패턴을 관찰

|||||-|||-|-|-|------ (25에 대한 최적의 솔루션)

로 묘사 될 수있다

 0  |
-1  |                  
+2   |                 -
-3    |               -
+4     | |           -
-5      - |         -
+6         | | | | -
-7          - - - -

여기서 끝의 각 총계 값은 (각 레벨의 값에 '|'s의 수를 곱한)의 합입니다. 예를 들어 위와 같이 -1*1 + 2*1 - 3*1 + 4*2 - 5*1 + 6*4 = 25합니다. 이것을 사용하여 다른 답변과 비슷한 결과를 생성하는 간단한 솔루션을 작성했습니다.

나는 가능한 모든 최적 높이를 테스트하기 때문에 이것이 최적의 솔루션이라고 생각합니다 (실제로 필요한 것보다 더 많은 것을 테스트합니다). 그리고 솔루션에는 항상 마지막 레이어 외에 두 개의 '|'가있는 최대 하나의 레이어가 포함되어 있다고 확신합니다 양수에 대해서는 보장하지만 음수에 대해서는 100 % 확신 할 수 없음).

def solution(num):
    if num == 0:
        return '|'

    neg = num<0
    num = abs(num)
    high = int(num**0.5)

    def sub(high):
        counts = [1]*high
        total = num - (high+neg)/2

        if total%high == 0:
            counts[-1] += total/high
        else:
            counts[-1] += total/high
            if (total%high)%2==1 and not neg:
                counts[-1] += 1
                counts[-(total%high)-1] += 1
            elif (total%high)%2==0 and neg:
                counts[(total%high)-2] += 1
                counts[0] += 1
            else:
                counts[total%high-1] += 1

        string = ""
        for c in counts[::-1]:
            string = '|-'*(c-1)+'|'+string+'-'
        return '|'+string

    return min((sub(h) for h in range(2-neg,2*high+2,2)), key=lambda s: len(s))

테스트에 사용한 코드는 다음과 같습니다.

string = "-8607 -6615 -6439 -4596 -4195 -1285 -72 12 254 1331 3366 3956 5075 5518 5971 7184 7639 8630 9201 9730"
total = 0

def string_to_binary(string):
    total = 0
    for i,char in enumerate(string[::-1]):
        total += (char=='|')*(2**i)
    return total

def stickstack(bits,length):
    stack = []
    for i in range(length):
        d,bits = divmod(bits,2**(length-i-1))
        if d == 1:
            stack.append(len(stack))
        else:
            stack[-2] -= stack[-1]
            stack = stack[:-1]
    return stack

for num in string.split():
    s = solution(int(num))
    print '%s:' % num
    print s
    result = stickstack(string_to_binary(s),len(s))
    print 'Result: %s' % result
    print 'Length: %s' % len(s)
    total += len(s)
    print

print 'Total length: %s' % total

2
훌륭한 솔루션! 나는 점수가 최적이라고 생각하고 (내 브 루트 포스 계산을 기반으로) 설명을 바탕으로 알고리즘이 항상 최상의 솔루션을 제공한다고 생각합니다.
randomra

@randomra 나는 그것이 그럴 가능성이 있다고 생각하지만 약 +/- 100까지만 강요 당했기 때문에 그것이 반드시 최고라고 말할 수는 없었지만 지금은 그것에 대해 생각할 수 없습니다. 어떻게 더 잘할 수 있는지.
KSab

+1 매우 좋습니다. 어떻게 시도 할 수 있습니까? 어떤 파이톤? (나는 파이썬 전문가가 아니며 실수로 내 노트북에 파이썬 3.4가 설치되어 있음).
edc65

@ edc65 테스트 할 코드를 추가했습니다. 또한 이것은 Python 2.7을 사용하므로 print 문과 같은 것은 Python 3에서 작동하지 않습니다.
KSab

가치가있는 것에 대해, 나는이 결과가 최적이라는 것을 확인할 수 있습니다 : 나는 최대 450의 길이 (그리고 여전히 실행중인)를 검증하는 무차별 대입 솔루션 (BFS)을 시도했습니다. 같은 결과가 나옵니다.
edc65

12

자바, 5208 5240 5306 6152

이것은 재귀 함수로, 목표에 더 가까워지고 5 단계 (대개 1 단계) 내에있을 때의 기본 사례가 있습니다.

기본적으로, 당신은 얻을 수 (a*b)+(a/2)에 대한 (a+b)*2간단한 패턴 스틱. 경우 a홀수, 결과는 음수가 될 몇 가지 이상한 논리가 리드 그렇게 할 것이다.

2 31 -1의 경우 1 분 정도 소요되며 길이는 185,367입니다. 그러나 모든 테스트 사례에서 거의 즉시 작동합니다. 4*(sqrt|n|)평균 점수 입니다. 가장 긴 개별 테스트 사례는 9730입니다. 397 길이의 스틱 스택이 생성됩니다.

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||-|||||||||||||||||||||-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|--------------------------------------------------------------------------------------------------|-

최신 정보:

기본 패턴에서 더하거나 빼는 더 짧은 방법을 찾았습니다. 다시 선두에 (지금)!


하네스 및 테스트 케이스 :

import static java.lang.Math.*;

public class StickStacker {

    public static void main(String[] args){
        StickStacker stacker = new StickStacker(); 
        int tests[] = {-8607,-6615,-6439,-4596,-4195,-1285,-72,12,254,1331,3366,3956,5075,5518,5971,7184,7639,8630,9201,9730};
        int sum = 0;
        for(int test : tests){
            String sticks = stacker.stickStack3(test);
            sum += sticks.length();
            System.out.println("In: " + test + "\t\tLength: " + sticks.length());
            System.out.println(sticks+"\n");
        }
        System.out.println("\n\nTotal: "+sum);          
    }

    String stickStack3(int n){return"|"+k(n);}
    String k(int n){
        String o="";
        int q=(int)sqrt(abs(n)),a,b,d=1,e=0,c=1<<30,
        z[]={232,170,42,10,2,0,12,210,52,844,212};
        a=n>0?q:-q;
        a-=n>0?a%2<1?0:1:a%2<0?0:-1;

        for(b=0;b<abs(a)+10;b++)
            if(abs(n-(a*b+a/2-(n>0?0:1)))<abs(a)&&abs(a)+b<c){
                    c=abs(a)+b;
                    d=a;e=b;
            }

        for(a=0;a++<e;)o+="-|";
        for(a=0;a++<abs(d);)o="|"+o+"-";

        c=n-(d*e+d/2-(n>0?0:1));
        if(c>0&&c<abs(d)){
            if(c%2==0)
                o=o.substring(0,c)+"-|"+o.substring(c);
            else
                o=o.substring(0,c+1)+"-|"+o.substring(c+1)+"|-";
            c=0;
        }else if(c<0&-c<abs(d)){
            if(c%2!=0)
                o=o.substring(0,-c)+"-|"+o.substring(-c);
            else
                o=o.substring(0,-c-1)+"-|"+o.substring(-c-1)+"|-";  
            c=0;
        }

        return n==0?"":n<6&&n>-6?
                Long.toBinaryString(z[n+5])
                .replaceAll("0","-")
                .replaceAll("1","|"):
                o+k(c);
    }
}

정확한 타이의 경우는 거의 없을 것입니다.


2 ^ 31에 대한 점수가 확실합니까? 2 ^ 30의 내 점수는 131099이고 2 ^ 31-1의 경우 185369입니다.
edc65

@ edc65 잘못 입력해야합니다. 어쨌든, 알아 차리고 경쟁 해 주셔서 감사합니다. 이제 내가 더 잘할 수 있는지
살펴볼

4

자바 스크립트 (ES6) 5296 6572

편집 설명에서 말했듯이 정수 방정식을 푸는 것이 좋지 않습니다. b 값에 대한 나의 추측은 그리 좋지 않았으므로 시도 할 값의 범위를 넓혔습니다. 그리고 (와우) 나는 지금 이끌고 있습니다.

2 버그 수정, 동일한 결과를 편집하십시오 . 나는 아이디어가 있지만 그것을 못 박을 수 없다.

바이트 : ~ 460, 상당히 골프. 32 비트 정수에서 작동하며 런타임은 0 근처입니다.

코드는 아래의 F 코드입니다 (스 니펫에 숨겨져 있음).
테스트 할 스 니펫을 실행하십시오 (FireFox에서).

설명

우선 양수. "베이스"로 시작하십시오 (원하는 경우 CJam에서 시도하고 공백을 허용하십시오)

| gives 0  
||| -- gives 1
||||| ---- gives 2
||||||| ------ gives 3 

요약 : 1 스틱, b * 2 스틱, b * 2 대시

그런 다음 하나 이상의 '-|'를 추가하십시오. 중간 분할. 각각은 시작베이스의 두 배인 고정 증분을 추가하며 여러 번 반복 할 수 있습니다. 따라서 우리는 b = base, r = in repeat repeat factor를 갖는 공식을 가지고 있습니다

v=b+r*2*b

b=1, r=0 to 3, inc=2
| || -- 1 
| || -| -- 3 
| || -| -| -- 5 
| || -| -| -| -- 7

b=3, r=0 to 3, inc=6
| |||||| ------ 3
| |||||| -| ------ 9
| |||||| -| -| ------ 15
| |||||| -| -| -| ------ 21

만나다? 더하기 값은 빠르게 증가하며 각 추가는 여전히 2 자입니다. 기본 증분은 매번 4자를 더 제공합니다.

v와 수식 v = b + r * 2 * b가 주어지면 2 개의 정수 b와 r을 찾아야합니다. 나는 이런 식의 전문가는 아니지만 b = int sqrt (v / 2)는 좋은 출발 추측입니다.

그런 다음 v와 가까운 값을 제공하는 r과 b가 있습니다. 반복 증가 (||-) 또는 감소 (|-)로 정확하게 v에 도달합니다.

수식이 비슷하지만 같지 않은 음수에 대해 동일한 추론을 따르십시오.


1

자바 스크립트, 398710

코드의 94 바이트 / 문자

나는 해결책을 생각해 냈습니다! ... 그리고 Sparr의 답변을 읽으면 정확히 동일합니다.

js는 약간의 문자를 허용하므로 어쨌든 게시 할 것이라고 생각했습니다.

다음은 코드의 축소되지 않은 버전입니다.

function p(a){
    s = "";
    if(a<=0){
        for(i=0; i<-2*a-1;i++)
            s="|"+s+"-";
        return "|"+s;
    }
    return "|"+p(0-a)+"-";
}

1
좋아, 우리가 398710 솔루션을 골프로 삼고 있다면 게임을 시작하십시오! 누군가 cjam 또는 pyth를 통해 와서 우리 둘 다 이길 것입니다 :(
Sparr

1

Python, 398710 (71 바이트)

가장 간단한 해결책이라고 생각합니다. 스틱 스택의 4 * n (+/- 1)자를 사용하여 n을 나타냅니다.

def s(n):return'|'*(n*2+1)+'-'*n*2 if n>=0 else'|'*(n*-2)+'-'*(n*-2-1)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.