左边四个步骤:毒蛇。右边的四个步骤:悬崖。不要死!


28

介绍

假设一下,如果在毒蛇和悬崖只有2步之遥,而不是三个。

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

不幸的是,你是一个虐待狂酷刑者的俘虏。您必须每转一圈向左或向右迈出一步。如果您不这样做,他们会立即将您射杀。您可以事先计划好您的步骤,但是一旦您迈出第一步,就无法更改您的计划。(也不要涉足,他们会射击你的。)

突然想到一个聪明的主意...

啊! 我可以左右交替走!右移,左移,右移,左移,依此类推...

啊啊啊,没那么快。就像我说的那样,酷刑者是虐待狂。他们可以选择是否要执行每一步,第二步或第三步,依此类推。因此,如果您天真地选择顺序,RLRLRL...那么它们会迫使您采取第二步,即从开始LL。哦哦!你被毒蛇咬了!黑暗笼罩了你,其他一切都消失了。

实际上,您还没有死。您仍然必须提出您的计划。经过几分钟的思考,您意识到自己注定要失败。无法计划出一系列步骤来保证您的生存。你能想到的最好的就是RLLRLRRLLRR1 11个安全步骤,仅此而已。如果第十二步是R,那么拷问者将使您迈出每一步,然后最后三步将您带离悬崖。如果第十二步是L,那么拷问者将使您每走第三步(LRLL),这将使您正确地进入毒蛇及其致命叮咬的怀抱。

您选择R第12步,希望能够尽可能长地延迟您的灭亡。随风在你的耳边咆哮,你自己想知道...

如果我有三个步骤怎么办?


扰流板警报!

你仍然会死。事实证明,无论您采取了多少步骤,无论您做出何种选择,都会有一点,您的折磨者可以选择一系列步骤来确保您满足致命的命运。2但是,如果毒蛇和悬崖距离酒店只有3步之遥,那么您总共可以采取1160个安全步骤;而如果距离它们又有4步之遥,则至少有13,000个安全步骤!3

挑战

给定一个整数n < 13000n假设悬崖和毒蛇相距四个步骤,则输出一系列安全步骤。

规则

  • 可以是完整程序或功能。
  • 输入可以通过STDIN或等效输入,也可以作为函数参数。
  • 输出必须有两个不同的字符(其可以是+/-R/L1/0,等等)。
  • 输出中的任何空格都无关紧要。
  • 不允许对解决方案进行硬编码。这将使这一挑战变得微不足道。
  • 您的程序(理论上)应该在相当长的时间内完成。在这种情况下,n=13000可能需要一个月的时间,但不应该花一千年或更长时间。也就是说,没有蛮力。(嗯,至少要设法避免它。)
  • 终身红利:提供一系列2000安全的步骤。如果您这样做,酷刑者将对您的坚韧,毅力和前瞻性印象深刻,以至于他们会让您活下去。这一次。(将此序列作为二进制数进行处理,并提供等效的十进制数进行验证。这是为了奖励很快就能完成的答案,因为答案需要很长时间。)
  • 分数:字节,除非您有资格获得奖金-乘以0.75

生存!


1 Numberphile的一位明星James Grime在他的YouTube频道上提供了关于此问题和“解决方案”的很好的解释,网址为https : //www.youtube.com/watch?v= pFHsrCNtJu4 。

2特伦斯·陶(Terence Tao)最近证明了这个有80年历史的猜想,即鄂尔多斯的差异问题。这是《 Quanta杂志》上一篇非常不错的文章:https : //www.quantamagazine.org/20151001-tao-erdos-discrepancy-problem/

3资料来源:鲍里斯·科涅夫(Boris Konev)和阿列克谢·利西塔(Alexei Lisitsa)对鄂尔多斯差异猜想的SAT攻击。从此处检索:http : //arxiv.org/pdf/1402.2184v2.pdf


1
因此,如果我为解决n=13000,它的前2000条指令会赢得奖金吗?似乎毫无意义,所以您可能还有其他意思吗?
anatolyg 2015年

@anatolyg:从理论上讲,所有解决方案都应该能够n=13000在一年左右甚至十年之内完成处理。你要等一个月n=2000吗?可能不是。如果您这样做了,那么无论如何您都应该获得奖金。
El'endia Starman 2015年

Answers:


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范围内进行),使用魔术伏都教启发法逐步选择最先尝试的方法。

在我的(相当快)的计算机上,它可以在1秒内解决2000甚至4000。需要更多的RAM才能获得更大的数量;我在8GB范围内解决的最大输入是5023,耗时约30秒。

要求加分的2000步解决方案的十进制表示形式:

67629177464446960798008264442022667063957880432486338092706841703491740570274032860458934082821213021464065304260003487277917407152662394728833698812373924467640518368465012204980858438160127647802572983143425507448999967241207186701518207195015015739598846687434709056793597015487555707466358473564611432637890414593517116857771284711814076853125419306285869381974622557155019992727242896503018802441210966188045211779436703341152749688824296759097963388158731237092792251164105828728858516951458791084595247591674731645830905744761534078963607725435881491831508342871545788662307953494333833994658998

YbCJam中附加到它,以转换回二进制文件。

关于启发式:首先,我正在使用一种模式:每9个步骤尝试重复前9个步骤,除了每(9 * x)个步骤尝试重复第x个步骤。这是从我在python答案中下载并使用(硬编码)的解决方案中得到的启发。

我一直在跟踪偏离模式的次数,以及到达“边缘”的次数(距离死亡仅一步之遥)。启发式函数基本上是这两个数字和到目前为止已执行的步数的加权组合。

可以进一步调整试探法以提高速度,并且也有几种方法可以向其中添加随机因子。
实际上,我刚刚阅读了有关此问题的乘法函数,并且看起来可以提供重大改进(TODO:稍后实施)。

取消评论并评论:

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

对于暴力破解方法来说,这相当快,n = 223仅花费几秒钟,而n> = 224仅花费几秒钟。

说明: 跟踪字符串列表对(s,u)的列表,其中列表u使得u [i]是跟随字符串中每个ith步骤之后的当前位置。对于列表中的每个字符串,尝试添加“ L”或“ R”,然后更改列表中相交的值。(即,如果生成的字符串的长度为10,则根据您移动的方向从位置1,2,5和10处加上或减去1)。如果您超过3或-3,请扔掉新的一对,否则将其保留在列表中。最长的字符串保留在末尾。长度为n的字符串后,将其返回。


为什么是Python 2/3?
Rɪᴋᴇʀ

两者中的任何一个都相同。我应该指定其中之一吗?
摩擦瓜

也许你应该。我只是在想,因为我不知道这//在python 2中
可用

-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 '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.