Bốn bước bên trái: vipers. Bốn bước bên phải: một vách đá. Đừng chết!


28

Giới thiệu

Giả sử trong một khoảnh khắc rằng vipers và vách đá chỉ cách hai bước, thay vì ba.

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

Thật không may, bạn là một tù nhân của một kẻ tra tấn tàn bạo. Bạn phải bước một bước sang trái hoặc sang phải mỗi lượt. Nếu bạn không, họ bắn chết bạn ngay lập tức. Bạn được phép lên kế hoạch cho các bước của mình trước đó, nhưng một khi bạn thực hiện bước đầu tiên, bạn không thể thay đổi kế hoạch của mình. (Và cũng không có ý kiến ​​gì cả; họ sẽ bắn bạn.)

Đột nhiên, một ý tưởng sáng chói xuất hiện trong đầu ...

À! Tôi chỉ có thể thay thế bước sang phải và trái! Bước sang phải, bước sang trái, bước phải, bước sang trái, v.v.

Ah ah ah, không nhanh như vậy. Như tôi đã nói, kẻ tra tấn là tàn bạo. Họ có thể chọn xem bạn thực hiện từng bước, hay từng bước thứ hai hay mỗi bước thứ ba, v.v. Vì vậy, nếu bạn ngây thơ chọn trình tự RLRLRL...thì họ có thể buộc bạn thực hiện từng bước thứ hai, bắt đầu bằng LL. À! Bạn đã bị cắn bởi vipers! Bóng tối tràn qua bạn và tất cả những thứ khác biến mất ...

Thật ra là không, bạn chưa chết. Bạn vẫn phải đưa ra kế hoạch của bạn. Sau khi suy nghĩ về nó trong vài phút, bạn nhận ra mình đã cam chịu. Không có cách nào để lên kế hoạch cho một loạt các bước sẽ đảm bảo sự sống còn của bạn. Điều tốt nhất bạn có thể đến với là RLLRLRRLLRR. 1 Mười một bước an toàn và không còn nữa. Nếu bước thứ mười hai là R, thì Kẻ tra tấn sẽ bắt bạn thực hiện từng bước và sau đó ba bước cuối cùng sẽ đưa bạn ra khỏi vách đá. Nếu bước thứ mười hai là L, thì Kẻ tra tấn sẽ bắt bạn thực hiện bước thứ ba ( LRLL), điều này đặt bạn ngay vào ổ chuột và những vết cắn chết người của chúng.

Bạn chọn Rlà bước thứ mười hai, hy vọng sẽ trì hoãn sự sụp đổ của bạn càng lâu càng tốt. Với cơn gió gào thét bên tai, bạn tự hỏi ...

Nếu tôi có ba bước thì sao?


Cảnh báo spoiler!

Bạn vẫn sẽ chết. Hóa ra, cho dù bạn có bao nhiêu bước đi, sẽ có một số điểm mà cho dù bạn có lựa chọn nào đi chăng nữa, vẫn có một chuỗi các bước mà Kẻ tra tấn của bạn có thể chọn để đảm bảo bạn gặp được số phận chết chóc của mình. 2 Tuy nhiên, khi vipers và vách đá cách đó ba bước, bạn có thể thực hiện tổng cộng 1160 bước an toàn và khi cách chúng bốn bước, có ít nhất 13.000 bước an toàn! 3

Các thách thức

Cho một số nguyên duy nhất n < 13000, xuất ra một chuỗi các nbước an toàn, giả sử vách đá và vip cách đó bốn bước.

Quy tắc

  • Có thể là một chương trình đầy đủ hoặc một chức năng.
  • Đầu vào có thể được thực hiện thông qua STDIN hoặc tương đương, hoặc như là một đối số chức năng.
  • Đầu ra phải có hai nhân vật riêng biệt (có thể +/-, R/L, 1/0, vv).
  • Bất kỳ khoảng trắng trong đầu ra không quan trọng.
  • Mã hóa cứng một giải pháp không được phép. Điều đó sẽ tầm thường hóa thách thức này.
  • Chương trình của bạn sẽ (về lý thuyết) hoàn thành trong một khoảng thời gian tốt. Như trong, n=13000có thể mất một tháng, nhưng nó không nên mất một ngàn năm hoặc hơn. Đó là, không có lực lượng vũ phu. (Chà, ít nhất là cố gắng tránh nó.)
  • Phần thưởng cuộc sống: cung cấp một loạt các 2000bước an toàn. Nếu bạn làm điều này, Kẻ phản bội sẽ rất ấn tượng bởi sự kiên trì, kiên trì của bạn và nghĩ rằng họ sẽ cho bạn sống. Đây là một lần. (Coi chuỗi này là số nhị phân và cung cấp số thập phân tương đương để xác minh. Điều này nhằm thưởng cho các câu trả lời kết thúc nhanh chóng vì các câu trả lời được cho phép mất một thời gian rất dài.)
  • Điểm: byte , trừ khi bạn đủ điều kiện nhận thưởng - nhân với 0,75 .

Sống sót!


1 Có một lời giải thích tốt về vấn đề này và "giải pháp" của một trong những ngôi sao của Numberphile, James Grime, trên kênh YouTube của anh ấy tại đây: https://www.youtube.com/watch?v=pFHsrCNtJu4 .

2 Giả thuyết 80 năm tuổi này, được gọi là vấn đề khác biệt của Erdos, đã được Terence Tao chứng minh rất gần đây. Đây là một bài viết rất hay trên Tạp chí Quanta về điều này: https://www.quantamagazine.org/20151001-tao-erdos-discrepancy-probols/ .

3 Nguồn: Cuộc tấn công SAT vào Giả thuyết sai lệch Erdos , của tác giả Boris Konev và Alexei Lisitsa. Lấy từ đây: http://arxiv.org/pdf/1402.2184v2.pdf .


1
Vì vậy, nếu tôi đưa ra giải pháp cho n=13000, 2000 hướng dẫn đầu tiên của nó có giành được tiền thưởng không? Có vẻ vô nghĩa, vì vậy bạn có thể có ý nghĩa gì khác?
anatolyg

@anatolyg: Tất cả các giải pháp về mặt lý thuyết có thể xử lý n=13000trong vòng một năm, có thể là mười. Bạn sẽ chờ đợi một tháng cho n=2000? Có lẽ là không. Và nếu bạn làm , sau đó bạn xứng đáng nhận được tiền thưởng.
El'endia Starman

Câu trả lời:


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

Đầu vào được lấy làm đối số dòng lệnh.

Điều này cố gắng gần như tất cả các khả năng (hạn chế duy nhất là 8 bước đầu tiên chỉ nên đi trong phạm vi -1..1), từng bước một, sử dụng phép thuật kinh điển ma thuật để chọn cách thử trước.

Nó giải quyết 2000 và thậm chí 4000 trong vòng 1 giây trên máy tính (khá nhanh) của tôi. Cần thêm RAM cho số lượng lớn hơn; đầu vào lớn nhất tôi đã giải quyết trong vòng 8GB là 5023 và mất khoảng 30 giây.

Đại diện thập phân của giải pháp cho 2000 bước, như được yêu cầu cho phần thưởng:

67629177464446960798008264442022667063957880432486338092706841703491740570274032860458934082821213021464065304260003487277917407152662394728833698812373924467640518368465012204980858438160127647802572983143425507448999967241207186701518207195015015739598846687434709056793597015487555707466358473564611432637890414593517116857771284711814076853125419306285869381974622557155019992727242896503018802441210966188045211779436703341152749688824296759097963388158731237092792251164105828728858516951458791084595247591674731645830905744761534078963607725435881491831508342871545788662307953494333833994658998

Nối Ybvào nó trong CJam để chuyển đổi trở lại nhị phân.

Về heuristic: đầu tiên, có một mẫu tôi đang sử dụng: cứ sau 9 bước cố gắng lặp lại 9 bước đầu tiên, ngoại trừ mỗi bước (9 * x) cố gắng lặp lại bước thứ x. Điều này được lấy cảm hứng từ giải pháp tôi đã tải xuống và sử dụng (mã hóa cứng) trong câu trả lời python của tôi.

Tôi đang theo dõi số lần tôi đi chệch khỏi mô hình, và cũng là số lần tôi đã đến một "cạnh" (1 bước từ khi chết). Hàm heuristic về cơ bản là sự kết hợp có trọng số của 2 số đó và số bước được thực hiện cho đến nay.

Các heuristic có thể được điều chỉnh thêm để cải thiện tốc độ, và có một số cách để thêm một yếu tố ngẫu nhiên vào nó.
Trên thực tế, tôi vừa đọc về các hàm nhân liên quan đến vấn đề này và có vẻ như điều đó có thể mang lại sự cải thiện đáng kể (TODO: thực hiện điều này sau).

Ungolfed và bình luận:

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

"sau này" chờ hơn một năm
CalculatorFeline

1

Python 2, 236 byte

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

Điều này khá nhanh, đối với phương pháp brute-force-ish, chỉ mất vài giây cho n = 223, nhưng lâu hơn nhiều cho n> = 224.

Giải thích: Theo dõi danh sách các cặp danh sách chuỗi (s, u), trong đó danh sách u sao cho u [i] là vị trí hiện tại sau khi thực hiện theo từng bước thứ i trong chuỗi. Đối với mỗi chuỗi trong danh sách, hãy thử thêm "L" hoặc "R", sau đó thay đổi các giá trị trong danh sách giao nhau. (tức là nếu chuỗi kết quả có độ dài 10, hãy thêm hoặc trừ 1 từ vị trí 1,2,5 và 10, theo hướng bạn đã di chuyển). Nếu bạn vượt quá 3 hoặc -3, hãy ném cặp mới đi, nếu không hãy giữ nó trong danh sách. Các chuỗi dài nhất được giữ ở cuối. Khi bạn có một chuỗi có độ dài n, hãy trả lại nó.


Tại sao trăn 2/3?
Rɪᴋᴇʀ

Nó hoạt động như nhau trong một trong hai. Tôi có nên chỉ định một trong số họ?
Dưa ma sát

Có lẽ bạn nên. Tôi chỉ tự hỏi bởi vì tôi không biết rằng nó //có sẵn trong python 2.
R

-2

Python 2, 729 byte

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]

Tôi nghĩ rằng điều này đủ điều kiện nhận tiền thưởng nếu ý tưởng là "thưởng cho câu trả lời kết thúc nhanh chóng".

Tuy nhiên, đây là một câu trả lời khó mã hóa, không nằm trong tinh thần của thử thách (mặc dù không được phép rõ ràng khi tôi viết nó).


2
Cuối cùng, một câu trả lời! d ;-)
wizzwizz4
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.