สี่ก้าวไปทางซ้าย: งูพิษ สี่ก้าวไปทางขวา: หน้าผา อย่าตาย!


28

บทนำ

สมมติว่าช่วงเวลาที่งูพิษและหน้าผาอยู่ห่างออกไปเพียงสองก้าวแทนที่จะเป็นสามขั้น

            o
           ---
Hsss!       |
 ';;' ___  /_\  ___  _
                      |

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

ทันใดนั้นความคิดที่สดใสก็มาถึงใจ ...

Ah! ฉันสามารถสลับก้าวไปทางซ้ายและขวาได้! ขั้นตอนที่ถูกต้องขั้นตอนที่เหลือขั้นตอนที่ถูกต้องขั้นตอนที่เหลือและอื่น ๆ ...

อ่าอาไม่เร็วนัก อย่างที่ฉันพูดผู้ทรมานนั้นเป็นพวกซาดิสต์ พวกเขาจะเลือกไม่ว่าคุณจะทำทุกขั้นตอนหรือทุกขั้นตอนที่สองหรือทุกขั้นตอนที่สามเป็นต้น ดังนั้นหากคุณเลือกอย่างไร้เดียงสาลำดับแล้วพวกเขาสามารถบังคับให้คุณใช้เวลาทุกขั้นตอนที่สองซึ่งจะเริ่มต้นด้วยRLRLRL... LLเอ่อโอ้! คุณถูกงูพิษกัด! ความมืดปกคลุมคุณและทุกอย่างก็จางหายไป ...

ที่จริงแล้วคุณยังไม่ตาย คุณยังต้องเกิดขึ้นกับแผนของคุณ หลังจากคิดถึงเรื่องนี้สักครู่คุณก็ตระหนักว่าคุณกำลังถูกลงโทษ ไม่มีวิธีการวางแผนขั้นตอนต่าง ๆ ที่จะรับประกันความอยู่รอดของคุณ RLLRLRRLLRRดีที่สุดที่คุณสามารถขึ้นมามี 1สิบเอ็ดขั้นตอนที่ปลอดภัยและไม่มาก หากขั้นตอนที่สิบสองคือRTorturer จะทำให้คุณทำทุกขั้นตอนและจากนั้นสามขั้นตอนสุดท้ายจะส่งคุณออกจากหน้าผา หากขั้นตอนที่สิบสองคือLผู้ทรมานจะทำให้คุณทำทุกขั้นตอนที่สาม ( LRLL) ซึ่งจะทำให้คุณถูกต้องในฝูงของงูพิษและกัดกัดตายของพวกเขา

คุณเลือกRเป็นขั้นตอนที่สิบสองหวังที่จะชะลอการตายให้นานที่สุด ด้วยเสียงคำรามในหูของคุณคุณสงสัยในตัวเอง ...

ถ้าฉันมีสามขั้นตอนล่ะ


แจ้งเตือนสปอยเลอร์!

คุณยังจะตาย ไม่ว่าคุณจะมีกี่ก้าวก็จะมีบางจุดที่ไม่ว่าคุณจะเลือกแบบไหนก็ตามจะมีลำดับขั้นตอนที่ทรมานของคุณสามารถเลือกได้เพื่อให้แน่ใจว่าคุณจะได้พบกับชะตากรรมที่อันตราย 2อย่างไรก็ตามเมื่องูพิษและหน้าผาอยู่ห่างออกไปสามขั้นตอนคุณสามารถทำตามขั้นตอนที่ปลอดภัยทั้งหมด 1160 ขั้นตอนและเมื่อก้าวออกไปสี่ก้าวจะมีขั้นตอนที่ปลอดภัยอย่างน้อย 13,000 ขั้น! 3

ความท้าทาย

รับจำนวนเต็มเดียวn < 13000ออกลำดับnขั้นตอนที่ปลอดภัยสมมติว่าหน้าผาและงูพิษอยู่ห่างออกไปสี่ขั้นตอน

กฎระเบียบ

  • สามารถเป็นได้ทั้งโปรแกรมหรือฟังก์ชั่นเต็มรูปแบบ
  • อินพุตสามารถใช้ผ่าน STDIN หรือเทียบเท่าหรือเป็นอาร์กิวเมนต์ของฟังก์ชัน
  • การส่งออกจะต้องมีตัวละครสองตัวที่แตกต่างกัน (ซึ่งอาจจะเป็น+/-, R/L, 1/0ฯลฯ )
  • ช่องว่างใด ๆ ในผลลัพธ์ไม่สำคัญ
  • ไม่อนุญาตให้ใช้การเข้ารหัสอย่างหนัก นั่นจะทำให้ความท้าทายนี้เป็นเรื่องเล็กน้อย
  • โปรแกรมของคุณควร (ในทางทฤษฎี) เสร็จในเวลาที่เหมาะสม ในขณะที่n=13000อาจใช้เวลาเช่นเดือน แต่ก็ไม่ควรใช้เวลาเป็นพัน ๆ ปีหรือมากกว่า นั่นคือไม่มีกำลังดุร้าย (อย่างน้อยก็พยายามหลีกเลี่ยง)
  • โบนัสชีวิต:มอบชุดของ2000ขั้นตอนที่ปลอดภัย หากคุณทำสิ่งนี้ผู้ทรมานจะประทับใจในความดื้อรั้นความเพียรและความคาดหวังของคุณที่พวกเขาจะปล่อยให้คุณมีชีวิตอยู่ ครั้งนี้ (ปฏิบัติตามลำดับนี้เป็นเลขฐานสองและจัดให้มีทศนิยมเทียบเท่าสำหรับการตรวจสอบนี่มีจุดประสงค์เพื่อให้รางวัลแก่คำตอบที่เสร็จอย่างรวดเร็วเนื่องจากคำตอบนั้นใช้เวลานานมาก)
  • คะแนน: ไบต์เว้นแต่คุณจะมีสิทธิ์ได้รับโบนัส - คูณด้วย 0.75

อยู่รอด!


1มีคำอธิบายที่ดีของปัญหานี้และ "การแก้ปัญหา" โดยหนึ่งในดาวของ Numberphile เจมส์สกปรกมากกว่าในช่อง YouTube ของเขาอยู่ที่นี่: https://www.youtube.com/watch?v=pFHsrCNtJu4

2 การคาดคะเนอายุ 80 ปีนี้ซึ่งรู้จักกันว่าเป็นปัญหาความไม่ลงรอยกันของ Erdos ได้รับการพิสูจน์โดย Terence Tao เมื่อเร็ว ๆ นี้ นี่เป็นบทความที่ดีมากในนิตยสารควอนตั้มเกี่ยวกับเรื่องนี้: https://www.quantamagazine.org/20151001-tao-erdos-discrepancy-problem/

3ที่มา: การโจมตี SAT จาก Erdos Conjecture Conjectureโดย Boris Konev และ Alexei Lisitsa แปลจากที่นี่: http://arxiv.org/pdf/1402.2184v2.pdf


1
ดังนั้นถ้าฉันจะแก้ปัญหาสำหรับn=130002000 คำแนะนำแรกของมันจะได้รับโบนัสหรือไม่ ดูเหมือนไม่มีจุดหมายดังนั้นคุณอาจหมายถึงอย่างอื่นหรือ
Anatolyg

@anatolyg: การแก้ปัญหาทั้งหมดในทางทฤษฎีควรจะสามารถจัดการn=13000ภายในเช่นปีอาจจะสิบ คุณจะรอเดือนn=2000หรือไม่ อาจจะไม่ได้ และถ้าคุณทำเช่นนั้นคุณสมควรได้รับโบนัสอยู่ดี
El'endia Starman

คำตอบ:


6

Java, 915 * 0.75 = 686.25

import java.util.*;class E implements Comparable<E>{static
int n,m,t,u;byte[]a;int k=2,b,d;E(){a=new byte[5];a[1]=13;}E(E
x){a=Arrays.copyOf(x.a,n+1);k=x.k;d=x.d;b=x.b;}int
g(int x){return(a[x]+1)%3-1;}void s(int x,int y){a[x]=(byte)(a[x]/3*3+(y+3)%3);}void
S(int x,int y){a[x]=(byte)(a[x]%3+(y+3)*3);}E
w(int x){if(g(k)==-x)return null;E e=new E(this);e.s(k,x);e.S(e.k++,x);for(m=0;++m<k;)if(k%m<1){u=e.a[m]/3-3+x;if(u==(k<9?2:4)*x)return
null;e.S(m,u);if(u==3*x){e.b++;if(k+m<=n){if(e.g(k+m)==x)return
null;e.s(k+m,-x);}}}return e;}public int compareTo(E o){m=d-o.d+(b-o.b)/60+(o.k-k)/150;return
m==0?o.k-k:m;}public static void main(String[]a){n=Integer.valueOf(a[0]);Queue<E>q=new PriorityQueue<>();q.add(new
E());for(;;){E x=q.remove(),y;if(x.k>n){for(t=0;++t<x.k;)System.out.print((x.g(t)+1)/2);return;}t=x.g(x.k<9?1:x.k%9==0?x.k/9:x.k%9);y=x.w(t);if(y!=null)q.add(y);y=x.w(-t);if(y!=null){y.d++;q.add(y);}}}}

อินพุตถูกใช้เป็นอาร์กิวเมนต์บรรทัดคำสั่ง

สิ่งนี้พยายามเป็นไปได้เกือบทั้งหมด (ข้อ จำกัด เพียงอย่างเดียวคือ 8 ขั้นตอนแรกควรดำเนินการภายใน -1..1) ไปทีละขั้นตอนโดยใช้คาถาแก้ปริศนาวูดูเพื่อเลือกวิธีที่จะลองก่อน

มันสามารถแก้ปัญหา 2000 และแม้กระทั่ง 4,000 ภายใน 1 วินาทีบนคอมพิวเตอร์ของฉัน (เร็วพอสมควร) ต้องการ RAM มากขึ้นสำหรับจำนวนที่มากขึ้น อินพุตที่ใหญ่ที่สุดที่ฉันแก้ไขภายใน 8GB คือ 5023 และใช้เวลาประมาณ 30 วินาที

การแทนค่าทศนิยมของโซลูชันสำหรับ 2,000 ขั้นตอนตามที่ร้องขอสำหรับโบนัส:

67629177464446960798008264442022667063957880432486338092706841703491740570274032860458934082821213021464065304260003487277917407152662394728833698812373924467640518368465012204980858438160127647802572983143425507448999967241207186701518207195015015739598846687434709056793597015487555707466358473564611432637890414593517116857771284711814076853125419306285869381974622557155019992727242896503018802441210966188045211779436703341152749688824296759097963388158731237092792251164105828728858516951458791084595247591674731645830905744761534078963607725435881491831508342871545788662307953494333833994658998

ผนวกYbเข้าไปในCJamเพื่อแปลงกลับไปเป็นไบนารี

เกี่ยวกับฮิวริสติก: ก่อนอื่นมีรูปแบบที่ฉันใช้อยู่: ทุก 9 ขั้นตอนพยายามทำซ้ำ 9 ครั้งแรกยกเว้นทุกขั้นตอน (9 * x) ขั้นตอนที่พยายามทำซ้ำขั้นตอนที่ x นี่เป็นแรงบันดาลใจจากโซลูชันที่ฉันดาวน์โหลดและใช้ (ฮาร์ดโค้ด) ในคำตอบของหลาม

ฉันกำลังติดตามจำนวนครั้งที่ฉันเบี่ยงเบนไปจากรูปแบบและจำนวนครั้งที่ฉันได้รับ "ขอบ" (1 ขั้นตอนจากการตาย) ฟังก์ชันการเรียนรู้แบบฮิวริสติกนั้นเป็นการผสมผสานระหว่างตัวเลข 2 ตัวกับจำนวนขั้นตอน

ฮิวริสติกสามารถปรับแต่งเพิ่มเติมเพื่อปรับปรุงความเร็วและมีหลายวิธีในการเพิ่มปัจจัยแบบสุ่มลงไปด้วย
ในความเป็นจริงฉันเพิ่งอ่านเกี่ยวกับฟังก์ชันหลายหน้าที่สัมพันธ์กับปัญหานี้และดูเหมือนว่าสามารถให้การปรับปรุงที่สำคัญ (สิ่งที่ต้องทำ: ใช้สิ่งนี้ในภายหลัง)

Ungolfed และแสดงความคิดเห็น:

import java.util.*;

public class Erdos implements Comparable<Erdos> {
    static int n; // input (requested number of steps)
    static int m, t, u; // auxiliary variables

    byte[] a; // keeps each step and sum combined into 1 byte
    int k = 2; // number of steps + 1 (steps are 1-based)
    int edge; // number of times we got to an edge
    int diff; // number of differences from the expected pattern

    // start with one step
    Erdos() {
        a = new byte[5];
        set(1, 1);
        setSum(1, 1);
    }

    // copy constructor
    Erdos(Erdos x) {
        a = Arrays.copyOf(x.a, n + 1);
        k = x.k;
        diff = x.diff;
        edge = x.edge;
    }

    // get the x'th step (can be -1, 0 or 1)
    int get(int x) {
        return (a[x] + 1) % 3 - 1;
    }

    // set the x'th step
    void set(int x, int y) {
        a[x] = (byte) (a[x] / 3 * 3 + (y + 3) % 3);
    }

    // get the sum of every x'th step (should be within -3..3)
    int getSum(int x) {
        return a[x] / 3 - 3;
    }

    // set the sum of every x'th step
    void setSum(int x, int y) {
        a[x] = (byte) (a[x] % 3 + (y + 3) * 3);
    }

    // try to add a step with value x (1 or -1)
    Erdos grow(int x) {
        if (get(k) == -x) // predetermined step doesn't match
            return null;
        Erdos e = new Erdos(this);
        e.set(k, x);
        e.setSum(e.k++, x);
        for (m = 0; ++m < k;)
            if (k % m < 1) { // check all divisors of k
                u = e.getSum(m) + x; // updated sum
                if (u == (k < 9 ? 2 : 4) * x) // use limit 2 for the first 8 steps, 4 for the rest
                    return null; // dead
                e.setSum(m, u);
                if (u == 3 * x) { // we're at an edge
                    e.edge++;
                    if (k + m <= n) { // predetermine future step - should be going back
                        if (e.get(k + m) == x) // conflict
                            return null;
                        e.set(k + m, -x);
                    }
                }
            }
        return e;
    }

    public int compareTo(Erdos o) { // heuristic function
        m = diff - o.diff + (edge - o.edge) / 60 + (o.k - k) / 150;
        return m == 0 ? o.k - k : m;
    }

    public static void main(String[] a) {
        n = Integer.valueOf(a[0]);
        Queue<Erdos> q = new PriorityQueue<>();
        q.add(new Erdos());
        for (;;) {
            Erdos x = q.remove(), y;
            if (x.k > n) { // we made it
                for (t = 0; ++t < x.k;)
                    System.out.print((x.get(t) + 1) / 2);
                return;
            }
            t = x.get(x.k < 9 ? 1 : x.k % 9 == 0 ? x.k / 9 : x.k % 9); // next step based on the pattern
            y = x.grow(t);
            if (y != null)
                q.add(y);
            y = x.grow(-t);
            if (y != null) {
                y.diff++;
                q.add(y);
            }
        }
    }
}

"ภายหลัง" รอเกินหนึ่งปี
CalculatorFeline

1

Python 2, 236 ไบต์

n=input();r=len;u=[("",[0]*(n//4))]
while n>r(u[-1][0]):
 y,t=u.pop()
 for c in 0,1:
  s=t[:];u+=(y+"LR"[c],s),
  for i in range(r(s)):
   if-~r(y)//-~i*-~i==-~r(y):s[i]+=2*c-1;
   if abs(s[i])>3:u.pop();break;
print(u[-1][0])

วิธีนี้ค่อนข้างเร็วสำหรับวิธี brute-force-ish ใช้เวลาเพียงไม่กี่วินาทีสำหรับ n = 223 แต่นานกว่าสำหรับ n> = 224

คำอธิบาย: ติดตามรายการของรายการสตริงคู่ (s, u) โดยที่รายการ u เป็นเช่นนั้น u [i] คือตำแหน่งปัจจุบันหลังจากทำตามทุกขั้นตอนในสตริง สำหรับแต่ละสายอักขระในรายการให้ลองเพิ่ม "L" หรือ "R" จากนั้นเปลี่ยนค่าในรายการที่ตัดกัน (เช่นถ้าสตริงผลลัพธ์มีความยาว 10 ให้เพิ่มหรือลบ 1 จากตำแหน่ง 1,2,5 และ 10 ตามทิศทางที่คุณย้าย) หากคุณมีมากกว่า 3 หรือ -3 ทิ้งคู่ใหม่ให้เก็บไว้ในรายการ สตริงที่ยาวที่สุดจะถูกเก็บไว้ในตอนท้าย เมื่อคุณมีสตริงที่มีความยาว n ให้ส่งคืน


ทำไมหลาม 2/3
Rɪᴋᴇʀ

มันทำงานเหมือนกันทั้งสองอย่าง ฉันควรระบุหนึ่งในนั้นหรือไม่
Melon Fricative

น่าจะเป็นคุณควร ฉันแค่สงสัยเพราะไม่รู้ว่า//เป็นประโยชน์ในหลาม 2
R

-2

Python 2, 729 ไบต์

n=0
for x in"eJytVU2LwyAQPWzTvZjjspcsxFYTBdNuQSEF+///1jp+p5o0hYVSBl9nfOObNz1MlAgqzMcEEwQkDyIkFpDYCW0UnChbyZJiK2sfhDcYmu9hT0GdIPQvLduAmoCvvqEssvq84CVCpLzrNcOOspLhY6/KswB6FmoSxGPBcWts7lsMp/0q83da1hgC6k7GoqBir1ruAFIVvWIdTi++oGIAyZw8mkuG03uDDc+rEsSWTmFBwbLgtTF8hl1e/lpCigR7+pM5V9lIqVJBjStzKNRRQDp6UOrvwga6VFrGcWz6YHwLNYWUYeZfWO/DQTq7i4dAxixeszmtFEw7Cr5v9R3lRVF55TDzY6QRrSfzF9NLE7lAZ+vLnGgYLZ/FlCuoRcOugeFduHTqRWmyh1J91XpIndIbEk8jifL8hs8qQ8vjAVoGqhK5Tm/O5svpXd82QH4Azq05kYnhj93PzLbcTisFzXWfDqIC5zsq3jU7UUhSh1R3L4+i4HCXKlrGyywSBttPr2zpL4gCDPtk2HPN5tgZFomzSDPfGAlASus+e4KlLcjS0vPQ0f5/mR/r1s4PcxsgMLRSMp617AveCuup2OCAPBT6yltWrPO9azsbp6fphR87Lc7VzcbEt5F4Ydg/NzhXTA==".decode("base64").decode("zip"):n=n*64+ord(x)
print bin(n)[2:input()+2]

ฉันคิดว่าสิ่งนี้มีคุณสมบัติที่จะได้รับโบนัสเช่นกันหากความคิดคือ "เพื่อตอบแทนคำตอบที่เสร็จสิ้นอย่างรวดเร็ว"

อย่างไรก็ตามนี่เป็นคำตอบที่ยากซึ่งไม่ได้อยู่ในจิตวิญญาณของความท้าทาย (แม้ว่าจะไม่ได้รับอนุญาตอย่างชัดเจนเมื่อฉันเขียนมัน)


2
ในที่สุดคำตอบ! d ;-)
wizzwizz4
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.