왼쪽의 네 단계 : 독사. 오른쪽으로 네 걸음 : 절벽. 죽지 마!


28

소개

독사와 절벽이 3 단이 아닌 2 단 떨어져 있다고 가정 해 봅시다 .

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

불행히도 당신은 가학적인 고문의 포로입니다. 당신은 해야한다 굽이마다 왼쪽 또는 오른쪽 중 하나 조치를 취할. 당신이하지 않으면, 그들은 당신을 즉시 죽인다. 미리 단계를 계획 할 수 있지만 첫 단계를 한 후에는 계획을 변경할 수 없습니다. (그리고 멍청한 것도 없습니다. 그들은 당신을 쏠 것입니다.)

갑자기 밝은 생각이 떠 오릅니다 ...

아! 오른쪽과 왼쪽으로 스테핑을 번갈아 할 수 있습니다! 오른쪽 단계, 왼쪽 단계, 오른쪽 단계, 왼쪽 단계 등 ...

아 아 아, 그렇게 빠르지 않습니다. 내가 말했듯이, 고문은 비판적입니다. 그들은 당신이 모든 걸음, 두 번째 걸음 또는 세 번째 걸음 등을 선택할 수 있습니다. 따라서 순진하게 시퀀스 RLRLRL...를 선택하면 으로 시작하는 두 번째 단계마다 강제로 진행할 수 있습니다 LL. 어 오! 당신은 독사에게 물렸다! 어둠이 너를 휩쓸고 다른 모든 것은 사라져 버린다 ...

사실 아니, 아직 안 죽었어 여전히 계획을 세워야합니다. 몇 분 동안 그것에 대해 생각한 후에, 당신은 운명이라는 것을 알게됩니다. 생존을 보장하는 일련의 단계를 계획 할 방법이 없습니다. 당신이 생각 해낼 수있는 최선은 RLLRLRRLLRR입니다. 1 일레븐 안전 단계와 더 이상. 열두 번째 단계가 R이면, 고문관이 모든 걸음을 내딛고 마지막 세 단계는 절벽에서 당신을 보냅니다. 열두 번째 단계가 L이면, 고문관이 세 번째 단계 ( LRLL)를 수행하게하여 독사의 무리와 치명적인 물린 상처를 바로 잡을 수 있습니다 .

당신 R은 12 단계로 선택 하고 가능한 한 오래 당신의 죽음을 지연시키기를 ​​희망합니다. 당신의 귀에 바람이 울리면서 당신은 자신에게 궁금해합니다 ...

세 단계를 거치면 어떻게 되나요?


스포일러 경고!

당신은 여전히 ​​죽을 것입니다. 결과적으로, 당신이 얼마나 많은 단계를 밟든, 어떤 선택을 하든지 Torturer가 당신이 치명적인 운명을 충족시키기 위해 선택할 수있는 일련의 단계가 있습니다. 2 그러나 독사와 절벽이 3 걸음 떨어져 있으면 총 1160 개의 안전한 걸음을 내릴 수 있으며 4 걸음 떨어진 곳에는 최소한 13,000 개의 안전한 걸음이 있습니다!

도전

단일 정수가 주어지면 절벽과 바이퍼가 4 단계 떨어져 있다고 가정하고 안전한 단계 n < 13000시퀀스를 출력 n하십시오.

규칙

  • 전체 프로그램 또는 기능 일 수 있습니다.
  • 입력은 STDIN 또는 이와 동등한 것을 통해 또는 함수 인수로 취할 수 있습니다.
  • 출력이 있어야 두 가지 문자 (될 수있는 +/-, R/L, 1/0, 등).
  • 출력의 공백은 중요하지 않습니다.
  • 솔루션의 하드 코딩은 허용되지 않습니다. 그것은이 도전을 사소하게 만들 것입니다.
  • 귀하의 프로그램은 이론적으로 적절한 시간 내에 완료되어야합니다. 마찬가지로 n=13000한 달이 걸릴 수도 있지만 천 년 이상 걸리지 않아야합니다. 즉, 무차별적인 힘이 없습니다. (적어도 피 하려고 노력 하십시오.)
  • 생명 보너스 : 일련의 2000안전한 단계를 제공 합니다. 이렇게하면 고문이 당신의 끈기와 인내심에 깊은 감명을 받아 그들이 당신을 살게 해줄 것입니다. 이번엔 (이 순서를 이진수로 처리하고 확인을 위해 10 진수를 제공하십시오. 이는 답변에 시간이 오래 걸리면 빨리 끝나는 답변에 대한 보상입니다.)
  • 보너스에 0.75를 곱한 경우를 제외하고 점수 : 바이트 .

살아남아!


1 Numberphile의 스타 James James가 그의 YouTube 채널 ( https://www.youtube.com/watch?v=pFHsrCNtJu4) 에서이 문제와 "해결책"에 대해 잘 설명하고 있습니다 .

2 Erdos의 불일치 문제로 알려진이 80 세의 추측은 최근 Terence Tao에 의해 입증되었습니다. Quanta Magazine의 https://www.quantamagazine.org/20151001-tao-erdos-discrepancy-problem/ 에 대한 아주 좋은 기사가 있습니다 .

3 출처 : Boris Konev와 Alexei Lisitsa 의 Erdos 불일치 추측에 대한 SAT 공격 . 여기에서 검색 : http://arxiv.org/pdf/1402.2184v2.pdf .


1
따라서에 대한 솔루션을 만들면 n=13000처음 2000 지침에 보너스가 있습니까? 무의미한 것 같아서 아마도 다른 의미가 있습니까?
아나톨리 크

@anatolyg : 모든 솔루션은 이론적으로 n=130001 년, 아마도 10 년 안에 처리 할 수 ​​있어야합니다 . 한 달 동안 기다릴 예정 n=2000입니까? 아마 아닙니다. 당신이 만약 이렇게 , 당신은 어쨌든 보너스를받을 자격이.
El'endia Starman

답변:


6

자바, 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 안에 있어야한다는 것입니다). 단계별로 마술 부두 휴리스틱을 사용하여 먼저 시도하는 방법을 선택하십시오.

내 (정말 빠른) 컴퓨터에서 1 초 이내에 2000 및 4000을 해결합니다. 더 큰 숫자를 위해서는 더 많은 RAM이 필요합니다. 8GB 내에서 해결 한 최대 입력은 5023이며 약 30 초가 걸렸습니다.

보너스 요청에 따라 2000 단계에 대한 솔루션의 소수 표현 :

67629177464446960798008264442022667063957880432486338092706841703491740570274032860458934082821213021464065304260003487277917407152662394728833698812373924467640518368465012204980858438160127647802572983143425507448999967241207186701518207195015015739598846687434709056793597015487555707466358473564611432637890414593517116857771284711814076853125419306285869381974622557155019992727242896503018802441210966188045211779436703341152749688824296759097963388158731237092792251164105828728858516951458791084595247591674731645830905744761534078963607725435881491831508342871545788662307953494333833994658998

CJam 에 추가 Yb하여 이진으로 다시 변환하십시오.

휴리스틱에 대해 : 먼저, 내가 사용하고있는 패턴이 있습니다 : 매 9 단계마다 모든 (9 * x) 단계가 x 단계를 반복하려고 시도하는 것을 제외하고는 처음 9 단계를 반복합니다. 이것은 내가 파이썬 답변에서 다운로드하고 사용한 (하드 코딩 된) 솔루션에서 영감을 얻은 것입니다.

패턴에서 벗어난 횟수와 "가장자리"에 도달 한 횟수 (죽음에서 1 단계)를 추적하고 있습니다. 휴리스틱 함수는 기본적으로이 두 숫자와 지금까지 수행 된 단계 수의 가중치 조합입니다.

휴리스틱은 속도를 향상시키기 위해 추가로 조정할 수 있으며 임의의 요소를 추가하는 방법도 있습니다.
사실, 나는이 문제와 관련하여 곱셈 함수에 대해 읽었으며 상당한 개선을 제공 할 수있는 것처럼 보입니다 (TODO : 나중에 구현하십시오).

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

파이썬 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])

무차별 대입법에서는 n = 223의 경우 몇 초 밖에 걸리지 않지만 n> = 224의 경우 훨씬 더 오래 걸립니다.

설명 : 문자열 목록 쌍 (s, u) 목록을 추적하십시오. 여기서 목록 u는 문자열에서 모든 i 번째 단계를 수행 한 후 u [i]가 현재 위치가됩니다. 목록의 각 문자열에 대해 "L"또는 "R"을 추가 한 다음 목록에서 교차하는 값을 변경하십시오. (즉, 결과 문자열의 길이가 10 인 경우 이동 한 방향에 따라 위치 1, 2, 5 및 10에서 1을 더하거나 빼십시오). 3 또는 -3을 초과하면 새 쌍을 버리고 그렇지 않으면 목록에 보관하십시오. 가장 긴 줄은 끝에 유지됩니다. 길이가 n 인 문자열이 있으면 반환하십시오.


왜 파이썬 2/3입니까?
Rɪᴋᴇʀ

어느 쪽에서 나 동일하게 작동합니다. 그들 중 하나를 지정해야합니까?
Fricative Melon

아마 당신은해야합니다. //파이썬 2에서 사용할 수 있다는 것을 몰랐기 때문에 궁금했습니다 .
Rɪᴋᴇʀ

-2

파이썬 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.