Як курка перейшла дорогу?


16

Зграбний кулак. Ніхто не знає, чому курка перейшла дорогу, можливо, з іншого боку був гарний петух. Але ми можемо розібратися, як. Напишіть програму, яка зліва направо перетинає цю (або будь-яку) "дорогу".

1356 | 1738
3822 | 1424
3527   3718
9809 | 5926
0261 | 1947
7188   4717
6624 | 9836
4055 | 9164
2636   4927
5926 | 1964
3144 | 8254

Ваша програма "перетинає" її, рухаючись зліва направо. Ви починаєте з будь-якого числа в крайньому лівому стовпчику, який вам подобається. Звідти ви можете перейти до будь-якого сусіднього символу праворуч. Якщо ви почали з верхнього лівого кута, 1, ви можете перейти до 3 або 8. Кожне число, до якого ви переходите, включаючи стартовий номер, додається до суми. Пробіли не додають до вашої суми. "|" змушує вас рухатися вгору або вниз, а не десь праворуч. (Ви не можете рухатися вперед по цьому персонажу) Ваша мета - перейти на іншу сторону з найменшою можливою сумою. Ваша програма повинна роздрукувати суму в кінці, і вона повинна бути в змозі вирішити будь-яку дорогу. Переважно, він також може мати вхід для дороги, але це не потрібно. Ваша програма повинна надрукувати як шлях, так і суму. Виграє найменше байт коду.

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

Для більш чіткого конкретизації доріг, це в основному рядок тексту (Або масив стовпців або рядків, якщо ви вважаєте за краще так думати), що відповідає правилам символів, і не може бути нічого, АЛЕ ці символи в дорога. Тут може бути будь-яке число, пробіл, смужка ("|") або новий рядок. Якщо дорогу проклали п'яний хлопець, як у відповіді ProgrammerDan, це все-таки дійсна дорога, і ваша програма повинна мати можливість вирішити таку дорогу. Не вважається дорогою, якщо неможливо дістатися до іншої сторони (Наприклад, немає виходу з прямої смуги).

Ваша програма не повинна визначати, чи дорога недійсна.

Ключ:
Будь-яке число - додає число до вашої суми, рухайтесь вперед.
Пробіл - рухайтеся вперед, нічого не додається до вашої суми.
"|" - Рухайте вгору або вниз, до вашої суми нічого не додається.

EDIT: Приклад рішення, як пропонується. Я не можу зробити жахливо великий, я не можу потрапити на IDE, щоб вирішити це для мене банкомат.

Пройдіться цією маленькою дорогою:

9191 | 8282
1919 | 2727
5555   5555

Рішенням буде шлях 1, 1, 1, 1, простір, дільник, дільник, простір, простір, 2, 2, 2, 2 на загальну суму 12.

РЕДАКТИКА № 2: Рішення першої дороги з цього питання, визначене програмами Геобітів та народів, становить 0,2,0,1,,,, 1,4,1,4 на суму 13.


4
Чи можете ви включити принаймні один тестовий випадок із правильним рішенням? Також, чи може бути більше трьох |підряд?
Мартін Ендер

1
@timmy ви можете рухатись по діагоналі, поки він рухається вперед. Її можна торкнутися парою діагональних рухів.
CaffeineToCode

3
@ mbomb007 Якщо починати з верхнього кута. Оскільки ви можете почати будь-яку в лівій колонці, ви можете отримати0,2,0,1, , , ,1,4,1,4 -> 13
Geobits

1
Так. Ви можете рухатись лише брусками вгору або вниз, тому ви можете вибратися з них лише через пробіл.
CaffeineToCode

1
Для виходу вистачає просто витрат, чи потрібно вивести весь шлях?
ПрограмістDan

Відповіді:


3

Pyth, 168 143 141 байт [зараз сумісний п'яний шлях]

Мій тестовий випадок працює, але через непорозуміння з мого боку, він не працюватиме належним чином із початковим прикладом. Я працюю над її виправленням.

Зараз працюю за оригінальним прикладом та п'яними дорогами

Деякі дійсно трохи менш потворні коди:

=Z.dC,++\ `MUT\|++0UT=^T5Ltu+G]?&qeeG\|<heGhH+eGeHHtb,0hbKhohNum++hed@ZhhdtedC,H_y_y.b+N]YmhohNd.:++TGT3HCm.[d\ lh.MlZ.z.z*hl.z]]0j\,t.sK\ hK

Перевірте тут

Я перевірив його на дорозі 10 + 9 х 40.

6417443208|153287613
8540978161|726772300
7294922506 263609552
0341937695 498453099
9417989188 370992778
2952186385|750207767
7049868670 756968872
1961508589|379453595
0670474005 070712970
4817414691|670379248
0297779413|980515509
6637598208 090265179
6872950638 767270459
7375626432 439957105
1387683792|544956696
6974831376 545603884
0949220671|632555651
3952970630|379291361
0456363431|275612955
2973230054|830527885
5328382365|989887310
4034587060 614168216
4487052014|969272974
5015479667 744253705
5756698090|621187161
9444814561|169429694
7697999461|477558331
3822442188 206942845
2787118311|141642208
2669534759 308252645
6121516963|554616321
5509428225|681372307
6619817314|310054531
1759758306 453053985
9356970729|868811209
4208830142 806643228
0898841529|102183632
9692682718|103744380
5839709581|790845206
7264919369|982096148

Лише зауваження: отримання "IndexError: список індексів поза діапазоном" під час запуску за допомогою наданого тестового набору.
ПрограмістDan

@ProgrammerDan так роблю я
CaffeineToCode

1
@CaffeineToCode правда, але поняття "п'яна дорога" було додано після того, як я подав. Було б корисно знати, що являє собою дорогу. На підставі прикладів я припустив дві сторони з розділовою колоною
Брайан Тук,

1
@CaffeineToCode Один з найкращих способів написати гарне запитання - це просто написати більше прикладів - навіть без рішення. Якби дорога зі змінною шириною або багатосмуговою дорогою були дійсними, один "божевільний" приклад проілюстрував би її без додаткового описового тексту.
ПрограмістDan

1
@ProgrammerDan Ви просили цього. Моя тепер сумісна з DR (і коротше ... здогадуюсь, я наживаюсь)
Brian Tuck

4

Java, 955 байт

Очевидно, що я не збираюсь вигравати жодних нагород, будучи Явою та всіма, але я люблю цю проблему і хотів зайнятись власним вступом.

Особливості та обмеження:

  • Може підтримувати нерегулярні дороги (супер п’яні!), Включаючи змінну ширину, складні лінії тощо.
  • Очікує, що дорога буде введена як параметри виконання; версія ungolfed також підтримує читання з stdin, але оскільки метод введення не вказаний, версія golfed очікує найменшого!
  • Використовує деяку техніку динамічного програмування, яку я не використовував протягом, о, 6 років або близько того, щоб ефективно вирішити за час O (n * m), де n - рядки, а m - стовпці.
    • Вирішує справа наліво, відмічаючи найкращий напрямок від поточного індексу до наступного індексу.
    • "Рядки" обробляються шляхом розв’язання їх стовпця, а потім звернення до них, якщо вони доступні в наступному стовпці. Вони вирішуються, зберігаючи напрям вгору або вниз, з вартістю в кінцевому підсумку недоступного нелінійного.
  • Відстежує, але не друкує (у версії golf'd) стартовий індекс найкращого рішення.

Гаразд, досить джибби джабби. Версія для гольфу:

class C{public static void main(String[]a){int n=a.length,m=0,i=0,j=0,h=0,p=0,q=0,s=0,t=0,b=-1,c=2147483647,x=0,y=0;char[][]r=new char[n][];char u;for(String k:a){j=k.length();m=(j>m)?j:m;}for(String k:a)r[i++]=java.util.Arrays.copyOf(k.toCharArray(),m);int[][][]d=new int[n][m][2];for(j=m-1;j>=0;j--){for(i=0;i<n;i++){u=r[i][j];p=(u=='\0'||u==' '||u=='|'?0:u-'0');if(j==m-1)d[i][j][1]=p;else{if(u=='|')d[i][j][0]=-1;else{for(h=-1;h<2;h++){x=i+h;y=j+1;if(x>=0&&x<n){if(d[x][y][0]==-1){s=x-1;while(s>=0&&r[s][y]=='|')s--;t=x+1;while(t<n&&r[t][y]=='|')t++;if((s>=0&&t<n&&d[s][y][1]<d[t][y][1])||(s>=0&&t>=n)){t=d[s][y][1];s=4;}else{s=6;t=d[t][y][1];}d[x][y][0]=s;d[x][y][1]=t;}q=d[x][y][1]+p;if(d[i][j][0]==0||q<d[i][j][1]){d[i][j][0]=h+2;d[i][j][1]=q;}}}}}if(j==0&&(b<0||d[i][j][1]<c)){b=i;c=d[i][j][1];}}}String o="";i=b;j=0;while(j<m){u=r[i][j];if(u=='\0')j=m;else{o+=u+",";h=d[i][j][0]-2;if(h>1)i+=h-3;else{i+=h;j++;}}}System.out.println(o+"\b:"+c);}}

За моєю звичкою, github з кодом, що не перебуває в гольфі .

Рішення для "першої" дороги:

$ java C "1356 | 1738" "3822 | 1424" "3527   3718" "9809 | 5926" "0261 | 1947" "7188   4717" "6624 | 9836" "4055 | 9164" "2636   4927" "5926 | 1964" "3144 | 8254"
0,2,0,1, , , ,1,4,1,4:13

Другий приклад:

$ java C "9191 | 8282" "1919 | 2727" "5555   5555"
1,1,1,1, ,|,|, , ,2,2,2,2:12

Зразок Брайана Тука:

$ java C "6417443208|153287613" "8540978161|726772300" "7294922506 263609552" "0341937695 498453099" "9417989188 370992778" "2952186385|750207767" "7049868670 756968872" "1961508589|379453595" "0670474005 070712970" "4817414691|670379248" "0297779413|980515509" "6637598208 090265179" "6872950638 767270459" "7375626432 439957105" "1387683792|544956696" "6974831376 545603884" "0949220671|632555651" "3952970630|379291361" "0456363431|275612955" "2973230054|830527885" "5328382365|989887310" "4034587060 614168216" "4487052014|969272974" "5015479667 744253705" "5756698090|621187161" "9444814561|169429694" "7697999461|477558331" "3822442188 206942845" "2787118311|141642208" "2669534759 308252645" "6121516963|554616321" "5509428225|681372307" "6619817314|310054531" "1759758306 453053985" "9356970729|868811209" "4208830142 806643228" "0898841529|102183632" "9692682718|103744380" "5839709581|790845206" "7264919369|982096148"
2,1,0,1,5,1,2,1,1,1, ,1,0,1,2,1,2,3,0,1:26

Приклад Браяна: "П'яний"

6417443208 | 153287613
8540978161 | 726772300
7294922506 263609552
0341937695 498453099
9417989188 370992778
2952186385 | 750207767
7049868670 756968872
1961508589 | 379453595
0670474005 070712970
4817414691 | 670379248
0297779413 | 980515509
6637598208 090265179
6872950638 767270459
7375626432 439957105
1387683792 | 544956
697483176 5456034
09492201 | 6325551
395297030 | 3792913
 456363431 | 275612
  73230054 | 830527885
    8382365 | 989887310
    4587060 614168216
  87052014 | 96927297
 50479667 7442537
57566980 | 621187161
944481456 | 169429694
7697999461 | 477558331
3822442188 206942845
2787118311 | 141642208
2669534759 308252645
6121516963 | 554616321
5509428225 | 681372307
6619817314 | 310054531
1759758306 453053985
9356970729 | 868811209
4208830142 806643228
0898841529 | 102183632
9692682718 | 103744380
5839709581 | 790845206
7264919369 | 982096148
$ java C "6417443208|153287613" "8540978161|726772300" "7294922506 263609552" "0341937695 498453099" "9417989188 370992778" "2952186385|750207767" "7049868670 756968872" "1961508589|379453595" "0670474005 070712970" "4817414691|670379248" "0297779413|980515509" "6637598208 090265179" "6872950638 767270459" "7375626432 439957105" "1387683792|544956" "697483176 5456034" "09492201|6325551" "395297030|3792913" " 456363431|275612" "  73230054|830527885" "    8382365|989887310" "    4587060 614168216" "  87052014|96927297" " 50479667 7442537" "57566980 | 621187161" "944481456 | 169429694" "7697999461|477558331" "3822442188 206942845" "2787118311|141642208" "2669534759 308252645" "6121516963|554616321" "5509428225|681372307" "6619817314|310054531" "1759758306 453053985" "9356970729|868811209" "4208830142 806643228" "0898841529|102183632" "9692682718|103744380" "5839709581|790845206" "7264919369|982096148"
 , , , ,0,5,2,0,1, , , ,1,1,1,3,2:16

Рішення візуалізується:

09492201 | 6325551
395297030 | 3792913
\ 456363431 | 275612
 \ 73230054 | 830527885
  \ 8382365 | 989887310
   \ 4 \ 87060 614168216
  87/5 - \ 4 | 96927 \ 97
 50479667 \ 74425/7
57566980 | \ 62- / 87161
944481456 | \ / 69429694
7697999461 | 477558331

Насолоджуйтесь!

Редагувати: Зараз я просто демонструю (дві дороги зливаються! Чи може він це зробити?)

948384 | 4288324 324324 | 121323
120390 | 1232133 598732 | 123844
 293009 | 2394023 432099 | 230943
 234882 | 2340909 843893 | 849728
  238984 | 328498984328 | 230949
  509093 | 904389823787 | 439898
   438989 | 3489889344 | 438984
   989789 | 7568945968 | 989455
    568956 | 56985869 | 568956
    988596 | 98569887 | 769865
     769879 | 769078 | 678977
     679856 | 568967 | 658957
      988798 | 8776 | 987979
      987878 | 9899 | 989899
       999889 | | 989899
       989999 | | 989999
        989898 | | 998999
        989999 | | 999999
         989998 || 899999
         989998 || 998999

Рішення:

$ java C "948384 | 4288324   324324 | 121323" "120390 | 1232133   598732 | 123844" " 293009 | 2394023 432099 | 230943" " 234882 | 2340909 843893 | 849728" "  238984 | 328498984328 | 230949" "  509093 | 904389823787 | 439898" "   438989 | 3489889344 | 438984" "   989789 | 7568945968 | 989455" "    568956 | 56985869 | 568956" "    988596 | 98569887 | 769865" "     769879 | 769078 | 678977" "     679856 | 568967 | 658957" "      988798 | 8776 | 987979" "      987878 | 9899 | 989899" "       999889 |    | 989899" "       989999 |    | 989999" "        989898 |  | 998999" "        989999 |  | 999999" "         989998 || 899999" "         989998 || 998999"
 ,2,0,3,0,0, ,|,|, ,|,|, ,|,|, ,|,|, ,|,|, ,|,|, ,|,|, , , , , , , ,|, ,|, ,|, ,|, ,|, ,|, ,|,|, , ,1,0,7,2:15

(бонус: шлях від neololfed):

$ java Chicken < test5.txt
best start: 3 cost: 15
  -> 2 -> 0 -> 3 -> 0 -> 0 ->   -> | -> | ->   -> | -> | ->   -> | -> | ->   -> | -> | ->   -> | -> | ->   -> | -> | ->
  -> | -> | ->   ->   ->   ->   ->   ->   ->   -> | ->   -> | ->   -> | ->   -> | ->   -> | ->   -> | ->   -> | -> | ->
  ->   -> 1 -> 0 -> 7 -> 2 -> 15
/ -> - -> - -> \ -> / -> / -> - -> , -> , -> - -> , -> , -> - -> , -> , -> - -> , -> , -> - -> , -> , -> - -> , -> , ->
- -> , -> , -> / -> \ -> - -> - -> - -> / -> / -> ^ -> / -> ^ -> / -> ^ -> / -> ^ -> / -> ^ -> / -> ^ -> / -> , -> , ->
/ -> - -> \ -> \ -> - -> \ -> across

Деталі про алгоритм

Було запропоновано більш повне пояснення методики динамічного програмування, яку я застосовував, і ось тут:

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

Алгоритм:

  • Починаючи з самого правого стовпця і переходячи вліво, обчисліть наступне про кожну комірку в стовпці:
    • Підсумок руху з найнижчою вартістю, визначеного як поточна вартість комірки + найменша вартість комірки, доступна в наступному стовпці
    • Дія руху, яку потрібно здійснити, щоб досягти цієї найменшої вартості, як просто дійсний перехід від цієї комірки до іншої однієї комірки.
  • Труби відкладаються. Щоб вирішити трубу, потрібно обчислити повний стовпчик, тому ми не обчислюємо труби до наступного стовпця.
    • Визначаючи найменшу вартість комірки зліва від труби, ми спочатку обчислюємо найкращий напрямок руху по трубі - вона завжди буде вирішуватися або вгору, або вниз, тому ми обчислюємо її один раз.
    • Потім ми зберігаємо, як і всі інші комірки, найкращу вартість (визначається як вартість комірки, до якої ми доїжджаємо, подорожуючи по трубі вгору чи вниз) та напрямок руху, щоб досягти її.

Примітки:

Це воно. Ми скануємо один раз зверху вниз, справа наліво; єдині комірки, що торкаються (потенційно) більше, ніж один раз, - це труби, однак кожна труба "вирішується" лише один раз, тримаючи нас у вікні O (m * n).

Для обробки "непарних" розмірів карти я вирішив просто попередньо сканувати та нормалізувати довжину рядків, додаючи нульові символи. Нульові символи враховуються як "нульова вартість", так само як і труби та пробіли. Потім, друкуючи рішення, я припиняю витрати на друк або рухається, коли буде досягнуто краю нормалізованої дороги, або буде досягнуто нульового символу.

Краса цього алгоритму полягає в тому, що він дуже простий, застосовує однакові правила до кожної комірки, виробляючи повноцінне рішення шляхом вирішення O (m * n) підзадач, і з точки зору швидкості досить швидко. Він торгує пам'яттю, створюючи ефективно дві копії в пам'яті карти проїжджої частини, перша - для зберігання даних про "найкращу вартість", а друга - для зберігання даних "кращий рух" на комірку; це характерно для динамічного програмування.


Чи можете ви пояснити свій підхід до ліній трохи більше? Я також спробував (дещо інший) підхід до динамічного програмування, але застряг розібратися в цьому. Я також розглядав поступовий (рядковий за рядком) підхід для вирішення надзвичайно довгих доріг, не надто широких, не використовуючи занадто багато пам'яті; чи знаєте ви, чи є спосіб зробити це за час (O ^ m * 2 * n)?
dfeuer

@dfeuer Безперечно все в компромісах. Жоден із підрядних підходів, який я вважав, не міг обробити всі перестановки введення, не піддаючись часу O (m ^ n); це проблема стовпця за стовпцем за побудовою (рух, в основному, йде зліва направо - ефективне рішення DP йде справа наліво). Можливо, вам вдасться зробити O (m * n) підхід до вирішення рядків за рядком з простим оглядом і відкладеним поглядом вперед, але ви значно збільшуєте складність, не ймовірно, економивши багато пам’яті.
ПрограмістDan

Я думав, що якщо я не помиляюся, вам потрібно лише відстежувати найкращий шлях до цих пір, а для кожного квадрата в останньому оброблюваному ряду - найвідоміші шляхи від лівого краю до правого краю та до кожного квадрата праворуч у тому ж рядку. Це неправильно?
dfeuer

1
Спасибі! Ви можете скоротити код до краплі, визначивши cяк -1>>>1.
dfeuer

1
Я націлююсь на Haskell, який ускладнить змагання за довжину, але це те, що я найкраще знаю на сьогоднішній день.
dfeuer
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.