หมายเลข StickStack


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สำหรับกรณีทดสอบด้านล่าง คะแนนต่ำกว่าดีกว่า
  • การส่งของคุณจะถูกต้องเฉพาะเมื่อคุณรันโปรแกรมของคุณในทุกกรณีทดสอบและนับคะแนนของคุณ
  • คะแนนรองของคุณคือความยาวของโปรแกรมหรือฟังก์ชั่นการสร้างของคุณ

กรณีทดสอบการป้อนข้อมูล

(แต่ละหมายเลขเป็นกรณีทดสอบที่แตกต่างกัน)

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

โปรแกรมของคุณควรทำงานกับจำนวนเต็มใด ๆ (ซึ่งชนิดข้อมูลของคุณสามารถจัดการได้) ไม่เพียง แต่สำหรับกรณีทดสอบที่กำหนด โซลูชันสำหรับหมายเลขทดสอบไม่ควรฮาร์ดโค้ดในโปรแกรมของคุณ หากมีข้อสงสัยเกี่ยวกับการเข้ารหัสรหัสการทดสอบจะเปลี่ยนไป


ฉันขอแนะนำให้เพิ่มส่วนที่ระบุว่า "และทำงานในเวลาที่เหมาะสม" เพื่อป้องกันการใช้กำลังดุร้าย

@Reatity ที่บอกเป็นนัยใน "ถูกต้องเฉพาะเมื่อคุณเรียกใช้โปรแกรมของคุณในทุกกรณีการทดสอบ"
edc65

คำตอบ:


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
สุดยอดทางออก! ฉันเชื่อว่าคะแนนดีที่สุด (จากการคำนวณแบบ bruteforce ของฉัน) และตามคำอธิบายของคุณฉันคิดว่าอัลกอริทึมของคุณจะให้คำตอบที่ดีที่สุดเสมอ
randomra

@randomra ฉันคิดว่ามันน่าจะเป็นไปได้ แต่ฉันเป็นสัตว์เดรัจฉานที่ถูกบังคับมากถึงประมาณ +/- 100 ดังนั้นฉันจึงไม่พร้อมที่จะบอกว่ามันเป็นสิ่งที่ดีที่สุด แต่ตอนนี้ฉันคิดว่าฉันไม่เห็น มันจะทำได้ดีกว่านี้อย่างไร
KSab

+1 ดีมาก ฉันจะลองได้อย่างไร pyton อะไร (ฉันไม่ได้เป็นงูใหญ่ฉันเพิ่งติดตั้งงูหลาม 3.4 บนแล็ปท็อปของฉัน)
edc65

@ edc65 ฉันเพิ่มรหัสเพื่อทดสอบ และนี่คือการใช้ Python 2.7 ดังนั้นสิ่งต่าง ๆ เช่นคำสั่งพิมพ์จะไม่ทำงานกับ Python 3
KSab

สำหรับสิ่งที่คุ้มค่าฉันสามารถยืนยันได้ว่าผลลัพธ์นี้ดีที่สุด: ฉันลองใช้วิธีเดรัจฉานแรง (BFS จริง ๆ ) โดยตรวจสอบความยาวได้ถึง 450 (และยังทำงานอยู่) ผลลัพธ์เดียวกันกับคุณ
edc65

12

Java, 5208 5240 5306 6152

นี่เป็นฟังก์ชั่นวนซ้ำที่ใกล้กับเป้าหมายโดยมีเคสพื้นฐานสำหรับเมื่อมันได้รับภายใน 5 (ซึ่งมักจะเป็นเพียงขั้นตอนเดียว)

โดยทั่วไปคุณสามารถ(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 และ 185369 สำหรับ 2 ^ 31-1
edc65

@ edc65 ฉันต้องพิมพ์ผิด ฉันคิดว่ามันดูค่อนข้างน้อย ... อย่างไรก็ตามขอบคุณที่สังเกตและให้การแข่งขัน ตอนนี้เป็นเวลาที่จะดูว่าฉันสามารถทำได้ดีกว่านี้หรือไม่ :)
Geobits

4

JavaScript (ES6) 5296 6572

แก้ไขอย่างที่ฉันพูดในคำอธิบายของฉันฉันไม่เก่งในการแก้สมการจำนวนเต็ม การคาดเดาค่า b ของฉันไม่ดีนักดังนั้นฉันจึงเพิ่มช่วงของค่าที่จะลอง และ (ว้าว) ตอนนี้ฉันเป็นผู้นำ

แก้ไข 2 แก้ไขข้อผิดพลาดผลลัพธ์เดียวกัน ฉันมีความคิด แต่ไม่สามารถตอกตะปูลง

Bytes: ~ 460, ค่อนข้าง golfed มันทำงานกับจำนวนเต็ม 32 บิตเวลาทำงานใกล้ 0

รหัสคือฟังก์ชั่น F (ซ่อนอยู่ในตัวอย่าง) ด้านล่าง
เรียกใช้ตัวอย่างเพื่อทดสอบ (ใน FireFox)

คำอธิบาย

ตัวเลขบวกเริ่มต้นด้วย เริ่มต้นด้วย "ฐาน" (ลองใช้ CJam หากต้องการอนุญาตให้เว้นวรรค)

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

สรุป: 1 แท่งจากนั้น b * 2 แท่งจากนั้นจึงขีด b * 2

จากนั้นลองเพิ่ม '- |' หนึ่งรายการขึ้นไป ในการแยกกลาง แต่ละอันเพิ่มการเพิ่มทีตายตัวนั่นคือสองเท่าของฐานเริ่มต้นและสามารถทำซ้ำได้หลายครั้ง ดังนั้นเราจึงมีสูตรด้วย b = ฐานและ 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

ดู? ค่าเพิ่มจะเพิ่มขึ้นอย่างรวดเร็วและการเพิ่มแต่ละรายการยังคงเป็นเพียง 2 ตัวอักษร การเพิ่มฐานให้ 4 ตัวอักษรต่อครั้ง

รับ v และสูตรของเรา v = b + r * 2 * b เราต้องหา 2 ints b และ r ฉันไม่ใช่ผู้เชี่ยวชาญในสมการชนิดนี้ แต่ b = int sqrt (v / 2) เป็นการเริ่มต้นที่ดี

จากนั้นเรามี r และ b ที่ให้ค่าใกล้กับ v เราไปถึง v อย่างแน่นอนด้วยการเพิ่มขึ้นซ้ำ ๆ (|| -) หรือการลดลง (| -)

ทำตามเหตุผลที่เหมือนกันสำหรับตัวเลขลบอนิจจาสูตรจะคล้ายกัน แต่ไม่เท่ากัน


1

JavaScript, 398710

94 ไบต์ / ตัวอักษรของรหัส

ฉันคิดวิธีแก้ปัญหา! ... แล้วอ่านคำตอบของสปาร์และมันก็เหมือนกันทุกประการ

คิดว่าฉันจะโพสต์ต่อไปเพราะ 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
ตกลงถ้าเรากำลังเล่นกอล์ฟโซลูชั่น 39,8710 เกมบน! บางคนจะเข้ามาพร้อมกับ cjam หรือ pyth และเอาชนะเราทั้งคู่แม้ว่า :(
Sparr

1

Python, 398710 (71 ไบต์)

ฉันคิดว่าเป็นทางออกที่ง่ายที่สุด ใช้อักขระ stickstack จำนวน 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.