Чотири кроки ліворуч: гадюки. Чотири кроки праворуч: скеля. Не вмирайте!


28

Вступ

Припустимо на мить, що гадюка та скеля знаходяться лише за два кроки, а не за три.

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

Ви, на жаль, полонені садистських катувальників. Ви повинні робити крок або вліво, або вправо кожного кроку. Якщо ви цього не зробите, вони моментально застрелять вас. Ви можете заздалегідь спланувати свої кроки, але коли ви зробите перший крок, ви не зможете змінити свій план. (І жодних ослаблень; вони застрелять тебе.)

Раптом на думку приходить яскрава ідея ...

Ах! Я можу просто чергувати кроки праворуч і ліворуч! Крок вправо, крок вліво, крок вправо, крок вліво і так далі ...

А-а-а, не так швидко. Як я вже казав, катувальник - садист. Вони можуть вибрати, чи робити ви кожен крок, чи кожен другий крок, чи кожен третій крок тощо. Тож якщо ви наївно вибираєте послідовність, RLRLRL...то вони можуть змусити вас робити кожен другий крок, який починається з LL. Ой-ой! Вас вкусили гадюки! Чорнота налітає на вас, і все інше згасає ...

Насправді ні, ти ще не мертвий. Ви все ще повинні придумати свій план. Подумавши про це кілька хвилин, ти зрозумієш, що ти приречений. Немає способу спланувати ряд кроків, які гарантують ваше виживання. Найкраще, що можна придумати, - це RLLRLRRLLRR. 1 одинадцять безпечних кроків і не більше. Якщо дванадцятий крок R, то катувач змусить вас робити кожен крок, і тоді три останні кроки відсилають вас зі скелі. Якщо дванадцятий крок - це L, тортурист змусить вас зробити кожен третій крок ( LRLL), що підводить вас прямо до виводка гадюк та їх смертельного укусу.

Ви вибираєте Rяк дванадцятий крок, сподіваючись затримати смерть якомога довше. З вітром, що реве у вухах, ти дивуєшся собі ...

Що робити, якщо у мене було три кроки?


Спойлер попередження!

Ти все одно помреш. Як виявляється, незалежно від того, скільки кроків у вас є, буде якийсь момент, коли незалежно від того, який вибір ви зробите, існує послідовність кроків, які ваш мучитель може обрати, щоб забезпечити вам зустріч зі своєю смертельною долею. 2 Однак, коли гадюка та скеля знаходяться в трьох кроках, ви можете зробити загалом 1160 безпечних кроків, а коли вони в чотирьох кроках, є щонайменше 13000 безпечних кроків! 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 років, відома як проблема розбіжності Ердоса, була нещодавно доведена Теренсом Тао. Ось дуже приємна стаття про журнал Quanta про це: https://www.quantamagazine.org/20151001-tao-erdos-discrepancy-problem/ .

3 Джерело: Атака САТ на Концепцію розбіжності Ердоса , Борис Конев та Олексій Лисиця. Отримано звідси: http://arxiv.org/pdf/1402.2184v2.pdf .


1
Тож, якщо я прийму рішення n=13000, чи отримають перші 2000 інструкцій цього бонусу? Вам здається безглуздим, значить, ви, мабуть, мали на увазі щось інше?
anatolyg

@anatolyg: Теоретично з усіма рішеннями має бути можливість вирішуватись n=13000протягом року, а може й десяти. Ви збираєтесь чекати місяць 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), ідучи поетапно, використовуючи магічний евристичний вуду, щоб вибрати, який шлях спробувати перший.

Він вирішує 2000 і навіть 4000 протягом 1 секунди на моєму (досить швидкому) комп’ютері. Для більшої кількості потрібна оперативна пам’ять; найбільший вхід, який я вирішив у межах 8 Гб, - 5023, і це зайняло близько 30 секунд.

Десяткове представлення рішення на 2000 кроків, як вимагається для бонусу:

67629177464446960798008264442022667063957880432486338092706841703491740570274032860458934082821213021464065304260003487277917407152662394728833698812373924467640518368465012204980858438160127647802572983143425507448999967241207186701518207195015015739598846687434709056793597015487555707466358473564611432637890414593517116857771284711814076853125419306285869381974622557155019992727242896503018802441210966188045211779436703341152749688824296759097963388158731237092792251164105828728858516951458791084595247591674731645830905744761534078963607725435881491831508342871545788662307953494333833994658998

Додайте Ybйого в CJam, щоб перетворити назад у бінарне.

Про евристичний: по-перше, є шаблон, який я використовую: кожні 9 кроків намагаються повторити перші 9, за винятком кожного (9 * х) кроку, який намагається повторити x-й крок. Це натхнене рішенням, яке я завантажив і використав (жорстко) у своїй відповіді python.

Я стежу за тим, скільки разів я відхилився від шаблону, а також кількість разів потрапив до "краю" (1 крок від вмирання). Евристична функція - це, в основному, зважена комбінація цих 2 чисел та кількості кроків, зроблених до цього часу.

Евристика може бути додатково налаштована для підвищення швидкості, і є кілька способів додати до неї також випадковий коефіцієнт.
Насправді я щойно читав про мультиплікативні функції стосовно цієї проблеми, і, схоже, це може забезпечити значне вдосконалення (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])

Це досить швидко, для методу грубої сили-ish, що займає лише кілька секунд для n = 223, але набагато довше для n> = 224.

Пояснення: слідкуйте за списком пар (s, u) списку рядків, де список u такий, що u [i] є поточною позицією після виконання кожного першого кроку рядка. Для кожного рядка у списку спробуйте додати "L" або "R", а потім змінити значення у списку, що перетинаються. . Якщо ви перевищили 3 або -3, викиньте нову пару, інакше збережіть її у списку. Найдовші пасма зберігаються в кінці. Як тільки у вас є рядок довжиною n, поверніть його.


Чому python 2/3?
Rɪᴋᴇʀ

Це працює однаково і в одному. Чи варто вказати одну з них?
Фрикативна диня

Напевно, слід. Мені було просто цікаво, бо я не знав, що //це можливо в python 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.