StickStack番号


22

StickStackは、2つの命令のみを持つ非常にシンプルなスタックベースのプログラミング言語です。

  • | スタックの長さをスタックにプッシュします
  • -スタックから上位2つの要素をポップし、それらの差を押し戻します(second topmost - topmost

言語の詳細

  • スタックは、プログラムの開始時には空です。
  • すべての命令は、左から右に順番に実行されます。
  • スタックの数が2未満の場合、-命令は無効です。
  • 実行の終了時に、スタックには正確に1つの数値が含まれている必要があります。

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次(タイブレーカー)スコアは、生成するプログラムまたは関数の長さです。

入力テストケース

(各番号は異なるテストケースです。)

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

プログラムは、特定のテストケースだけでなく、任意の整数(データ型が処理できる整数)で動作するはずです。テスト番号のソリューションは、プログラムにハードコーディングしないでください。ハードコーディングに疑問がある場合は、テスト番号が変更されます。


総当たり攻撃を防ぐために、「そして、適切な時間内に実行する」という句を追加することをお勧めします。

「すべてのテストケースでプログラムを実行した場合にのみ有効」で暗示されている
@Reticality

回答:


7

Python 2-5188

時間的には非常に効率的であり、(おそらく)最適なソリューションのようです。私はそのようなパターンを観察しました

|||||-|||-|-|-|------ (25の最適なソリューション)

として描くことができます

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

ここで、最後の合計値は(各レベルの値に '|'の数を掛けた値)の合計です。したがって、上記の例では、があり-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とてもいい。どうやって試せますか?何パイトン?(私はパイニストではありませんが、偶然にPython 3.4をラップトップにインストールしています。)
edc65

@ edc65テストするためのコードを追加しました。また、これはPython 2.7を使用しているため、printステートメントなどはPython 3で動作しません
KSab

価値のあることについては、この結果が最適であることを確認できます。ブルートフォースソリューション(実際にはBFS)を試し、最大450の長さまで検証しました(まだ実行中です)。同じ結果があなたのものです。
edc65

12

Java、5208 5240 5306 6152

これは、5以内(多くの場合1ステップだけ)になったときの基本ケースを使用して、ターゲットに近づくエッジを持つ再帰関数です。

基本的には、シンプルなパターン(a*b)+(a/2)(a+b)*2スティックを取得できます。もしa奇数で、結果はそういくつかの奇妙なロジックにつながることが、負になります。

これには2 31 -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

JavaScript(ES6)5296 6572

編集説明で述べたように、整数方程式を解くのは苦手です。私のb値の推測はあまり良くなかったので、試す値の範囲を広げました。そして(すごい)私は今までにリードしています。

編集2バグ修正、同じ結果。アイデアはありますが、それを特定することはできません。

バイト:〜460、非常にゴルフ。32ビット整数で動作し、実行時間は0に近い。

コードは、以下のF関数(スニペットに非表示)です。
スニペットを実行してテストします(FireFoxで)。

説明

そもそも正の数。「ベース」から始めます(必要に応じてCJamで試してください。スペースを入れてください)

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

要約:1本の棒、次にb * 2の棒、次にb * 2のダッシュ

次に、1つ以上の「-|」を追加してみてください 真ん中のスプリット。それぞれが開始ベースの2倍の固定増分を追加し、何度も繰り返すことができます。したがって、b = baseとr = incrementの繰り返し係数を含む式があります

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

見る?addes値はすぐに増加し、各追加はまだ2文字のみです。基本インクリメントは、毎回さらに4文字を与えます。

vと式v = b + r * 2 * bが与えられると、2つの整数bとrを見つける必要があります。私はこの種の方程式の専門家ではありませんが、b = int sqrt(v / 2)が出発点として適切です。

次に、一緒にvに近い値を与えるrとbがあります。増分(||-)または減分(|-)を繰り返して正確にvに達します。

負の数についても同じ推論に従ってください。残念ながら、式は似ていますが等しくありません。


1

JavaScript、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
OK、398710ソリューションをゴルフするなら、ゲームを開始してください!誰かがチャムまたはピスでやって来て、私たち両方を打ち負かしますが、:(
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.