StickStack Numaraları


22

StickStack, yalnızca iki talimat içeren çok basit bir yığın tabanlı programlama dilidir:

  • | yığının uzunluğunu yığının üzerine iter
  • -üstteki iki öğeyi yığından çıkar ve farklarını geri iter ( second topmost - topmost)

Dil detayları

  • Program başlangıcında yığın boştur.
  • Tüm talimatlar soldan sağa sırayla uygulanır.
  • Yığında 2'den az sayı varsa, -talimat geçersizdir.
  • Uygulama sonunda yığının tam olarak bir sayı içermesi gerekir .

Herhangi bir tamsayı bir StickStack programı tarafından oluşturulabilir. Örneğin:

|||--||-- 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 kodunuzu değerlendirmek için bu çevrimiçi (CJam) değerlendiricisini kullanabilirsiniz . (Kod için @ Martin için teşekkürler.)

Görev

Girdi çıktısı olarak bir tamsayı numarası verilmiş bir program veya işlev yazmalı veya verilen sayıyı çıkaran bir StickStack programını temsil eden bir dize döndürmelisiniz.

puanlama

  • Birincil puanınız aşağıda verilen test durumları için StickStack programlarının toplam uzunluğu . Düşük puan daha iyidir.
  • Gönderiminiz yalnızca programınızı tüm sınav durumlarında çalıştırıp puanınızı saydıysanız geçerlidir.
  • İkincil (tiebreaker) puanınız, üretme programınızın veya işlevinizin uzunluğudur.

Giriş testi durumları

(Her numara farklı bir test durumudur.)

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

Programınız sadece verilen test durumları için değil (veri tipinizin kullanabileceği) tam sayılar için çalışmalıdır. Test numaralarının çözümleri programınıza kodlanmamalıdır. Kodlama şüphesi varsa, test numaraları değişecektir.


Ben kaba kuvvet önlemek için "Ve makul bir süre içinde çalışır" yazan bir cümle eklemenizi öneririm.

"Yalnızca tüm test
senaryolarında

Yanıtlar:


7

Python 2 - 5188

Zamanında oldukça verimli ve en uygun çözüm (muhtemelen) gibi görünüyor. Gibi bir desen olduğunu gözlemledim

|||||-|||-|-|-|------ (25 kişi için en uygun çözüm)

olarak tanımlanabilir

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

sondaki her toplam değerin toplamıdır (her seviyenin değeri '|' sayısı ile çarpılır). Yani yukarıda, biz var -1*1 + 2*1 - 3*1 + 4*2 - 5*1 + 6*4 = 25. Bunu kullanarak diğer cevaplara benzer çıktılar üreten ve çok kısa sürede bu çözümü yazdım.

Mümkün olan her uygun yüksekliği test ettiğimden (aslında gerekenden daha fazlasını test ediyorum) ve çözümün her zaman en az iki '|' in dışında bir katman içerdiğinden eminim (en iyisini yapabilirim) olduğuna inanıyorum. Bunu pozitif sayılar için garanti edin, ancak negatiflerden% 100 emin olmadığından emin olun).

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

İşte test etmek için kullandığım kod

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
Harika çözüm! Skorun optimal (bruteforce hesaplamama göre) olduğuna ve açıklamanıza göre algoritmasının her zaman en iyi çözümleri verdiğini düşünüyorum.
randomra

@randomra Bunun muhtemel olduğunu düşünüyorum, ama sadece +/- 100'e kadar kaba davrandım, bu yüzden mutlaka en iyisi olduğunu söylemeye hazır değildim, ama şimdi bunu göremiyorum. daha iyi nasıl yapılabilirdi.
KSab

+1 çok hoş. Nasıl deneyebilirim? Hangi piton? (Ben bir pythonist değilim, sadece yanlışlıkla dizüstü bilgisayarımda yüklü bir python 3.4 var).
edc65

@ edc65 Test etmek için kod ekledim; Ayrıca bu Python 2.7 kullanıyor, bu yüzden print cümleleri gibi şeyler Python 3 ile çalışmayacak
KSab

Ne olursa olsun, bu sonucun optimal olduğunu teyit edebilirim: bir kaba kuvvet çözümü denedim (gerçekten bir BFS), 450 uzunluğa kadar doğrulama (ve hala çalışıyor). Aynı sonuçlar senin.
edc65

12

Java, 5208 5240 5306 6152

Bu, hedefe daha yakın kenarları olan, tekrarlayan bir fonksiyondur, baz alındığında 5 olur (genellikle sadece bir adımdır).

Temel olarak, alabilirsiniz (a*b)+(a/2)için (a+b)*2basit desenli sopalarla. Eğer agarip, sonuç olumsuz bazı garip mantığı bu potansiyel böylece edecektir.

Bu , sonuç olarak 185,367 uzunluğunda, 2 31 -1 için bir dakika kadar sürer . Yine de tüm test durumlarında neredeyse anında çalışıyor. 4*(sqrt|n|)Ortalama puan alır. 9730397 uzunluktaki çubuk yığınına neden olan en uzun bireysel test durumu :

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

Güncelleştirme:

Temel düzenden toplama / çıkarma için daha kısa bir yol bulundu. Başa dön (şimdilik)!


Bir emniyet kemeri ve test durumları ile:

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);
    }
}

Beklenmedik bir durumda kesin bir şekilde golf (daha fazla) olacak.


2 ^ 31 için puanınızdan emin misiniz? 2 ^ 30 için puanım 131099 ve 2 ^ 31-1 için 185369.
edc65

@ edc65 Yanlış yazmış olmalıyım. Ben biraz düşük görünüyordu düşündüm ... Neyse, fark ve rekabeti verdiğiniz için teşekkürler. Şimdi daha iyisini
yapıp

4

JavaScript (ES6) 5296 6572

Düzenleme Açıklamamda söylediğim gibi, tamsayılı denklemleri çözmede iyi değilim. B değeri hakkındaki tahminim o kadar iyi değildi, bu yüzden denenecek değerler aralığını genişlettim. Ve (wow) Ben şimdiye kadar liderlik yapıyorum.

2 Hata düzeltme, aynı sonuçları düzenleyin. Benim bir fikrim var, ama çivileyemiyorum.

Bayt: ~ 460, oldukça golf. 0'a yakın çalışma süresi olan 32 bit tam sayılarda çalışır.

Bu kod, aşağıdaki F fonksiyonudur (snippet'te gizli).
Test etmek için pasajı çalıştırın (FireFox'ta).

açıklama

Olumlu sayılar, başlamak için. Bir "base" ile başlayın (isterseniz boşluklara izin verilirse CJam'ı deneyin)

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

Özet: 1 çubuk, sonra b * 2 çubuk, sonra b * 2 çizgi

Ardından bir veya daha fazla '- |' eklemeyi deneyin orta bölmede. Her biri, başlangıç ​​tabanının iki katı olan ve birçok kez tekrarlanabilen sabit bir artış ekler. Böylece, bir formülümüz var, b = base ve r = artış tekrar faktörü

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

Görmek? Adds değeri hızlı bir şekilde artmaktadır ve her ekleme hala sadece 2 karakterdir. Temel artış her seferinde 4 karakter verir.

V ve formülümüz v = b + r * 2 * b olduğunda, 2 inç b ve r'yi bulmamız gerekir. Bu tür bir denklemde uzman değilim, ama b = int sqrt (v / 2) iyi bir başlangıç ​​tahmindir.

Sonra birlikte bir v ve b var v. Yakınında v değerine yakın bir değer veriyoruz.

Negatif sayılar için aynı akıl yürütmeyi uygulayın, ne yazık ki formül benzer ancak eşit değil.


1

JavaScript, 398710

94 bayt / kod karakteri

Bir çözüm buldum! ... ve sonra Sparr'un cevabını okudum ve aynısıydı.

Yine de, js'nin daha az sayıda karaktere izin verdiği için onu göndereceğimi düşündüm.

İşte kodun unifified bir sürümü:

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

1
Tamam, 398710 çözümlerini golf oynuyorsanız, oyuna devam edin! birisi cjam veya pyth ile gelecek ve ikimizi de yenecek olsa da :(
Sparr

1

Python, 398710 (71 bayt)

Sanırım mümkün olan en basit çözüm. N'yi temsil etmek için 4 * n (+/- 1) stickstack karakterini kullanır.

def s(n):return'|'*(n*2+1)+'-'*n*2 if n>=0 else'|'*(n*-2)+'-'*(n*-2-1)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.