Come ha fatto il pollo ad attraversare la strada?


16

Cluck Cluck. Nessuno sa perché il pollo abbia attraversato la strada, forse c'era un gallo dall'altra parte. Ma possiamo capire come. Scrivi un programma che, da sinistra a destra, attraversi questa (o qualsiasi) "strada".

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

Il tuo programma "lo attraversa", spostandosi da sinistra a destra. Inizi su qualsiasi numero nella colonna più a sinistra che ti piace. Da lì, puoi spostarti su qualsiasi personaggio adiacente a destra. Se hai iniziato nell'angolo in alto a sinistra, 1, potresti passare a 3 o 8. Ogni numero a cui vai, incluso il numero iniziale, viene aggiunto a una somma. Gli spazi non si aggiungono alla tua somma. "|" ti costringe a spostarti verso l'alto o verso il basso, piuttosto che da qualche parte a destra. (NON PUOI andare avanti con questo personaggio) Il tuo obiettivo è arrivare dall'altra parte con la somma più piccola possibile. Il tuo programma deve stampare la somma alla fine e deve essere in grado di risolvere qualsiasi strada. Preferibilmente, potrebbe anche avere input per una strada, ma non è necessario. Il tuo programma deve stampare sia il percorso che la somma. Vince il minor numero di byte di codice.

Per chiarire, è possibile spostarsi diagnosticamente a meno che non ci si trovi su una barra verticale. Puoi muoverti su e giù solo quando ti trovi su una barra verticale.

Per una specifica più chiara delle strade, è fondamentalmente una stringa di testo (o una matrice di colonne o righe, se preferisci pensare in quel modo) che segue le regole dei caratteri, e non ci può essere nulla MA quei caratteri in la strada. Ci può essere qualsiasi numero, uno spazio, una barra ("|") o una nuova riga. Se una strada è stata lastricata da un ubriaco, come nella risposta di ProgrammerDan, è ancora una strada valida e il tuo programma deve essere in grado di risolverla. Non è considerata una strada se è impossibile raggiungere l'altro lato (ad esempio, non c'è via d'uscita da una linea retta di barre).

Il tuo programma non è tenuto a determinare se una strada non è valida.

Chiave:
qualsiasi numero: aggiunge il numero alla somma, vai avanti.
Spazio: vai avanti, nulla viene aggiunto alla tua somma.
"|" - Sposta su o giù, nulla viene aggiunto alla tua somma.

EDIT: una soluzione di esempio, come suggerito. Non posso farne uno orribilmente grande, non riesco a ottenere un IDE per risolverlo per me ATM.

Prendi questa piccola strada:

9191 | 8282
1919 | 2727
5555   5555

La soluzione sarebbe un percorso di 1, 1, 1, 1, spazio, divisore, divisore, spazio, spazio, 2, 2, 2, 2 per un totale di 12.

EDIT # 2: La soluzione alla prima strada su questa domanda, come determinato da Geobits e programmi di popoli, è 0,2,0,1,,,, 1,4,1,4 per un importo di 13.


4
Potresti includere almeno un caso di test con una soluzione corretta? Inoltre, potrebbero essercene più di tre |di fila?
Martin Ender,

1
@timmy puoi muoverti in diagonale, purché si muova in avanti. Può essere toccato con un paio di movimenti diagonali.
CaffeineToCode

3
@ mbomb007 Se inizia nell'angolo in alto. Poiché puoi iniziare da qualsiasi colonna a sinistra, puoi ottenere0,2,0,1, , , ,1,4,1,4 -> 13
Geobits il

1
Sì, lo fa. Puoi solo spostarti verso l'alto o verso il basso sulle barre, quindi puoi uscirne solo attraverso uno spazio.
CaffeineToCode

1
Per l'output, semplicemente il costo è sufficiente o deve essere prodotto l'intero percorso?
Programmatore:

Risposte:


3

Pyth, 168 143 141 byte [ora compatibile con Drunken Road]

Il mio caso di test funziona, ma a causa di un malinteso da parte mia, non funzionerà correttamente con l'esempio iniziale. Sto lavorando per risolverlo.

Ora funziona per esempio originale e strade ubriache

Alcuni codice VERAMENTE leggermente meno brutto :

=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

Provalo qui

L'ho provato su una strada 10 + 9 x 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

Solo una nota, ottenendo un "IndexError: elenca l'indice fuori intervallo" durante l'esecuzione utilizzando la suite di test fornita.
Programmatore:

@ProgrammerDan so do I.
CaffeineToCode

1
@CaffeineToCode vero, ma il concetto di "strada ubriaca" è stato aggiunto dopo l'invio. Sarebbe stato utile sapere cosa costituiva una strada. Sulla base degli esempi ho assunto 2 lati con una colonna divisoria
Brian Tuck,

1
@CaffeineToCode Uno dei modi migliori per scrivere una buona domanda è solo scrivere altri esempi, anche senza soluzione. Se la larghezza variabile o le strade a più corsie fossero valide, un esempio "pazzo" lo avrebbe illustrato senza alcun testo descrittivo aggiuntivo.
Programmatore:

1
@ProgrammerDan L'hai chiesto. Il mio è ora compatibile con DR (e più breve ... suppongo che stia prendendo piede)
Brian Tuck,

4

Java, 955 byte

Ovviamente non vincerò alcun premio, essendo Java e tutti, ma adoro questo problema e volevo inserire la mia voce.

Caratteristiche e limiti:

  • Può supportare strade irregolari (super ubriache!) Comprese larghezze variabili, linee complesse, ecc.
  • Si aspetta che la strada venga inserita come parametro durante l'esecuzione; la versione ungolf supporta anche la lettura da stdin, ma poiché il metodo di input non è stato specificato la versione golf si aspetta il più piccolo!
  • Utilizza una tecnica di programmazione dinamica che non ho usato in, oh, 6 anni circa per risolvere in modo efficiente nel tempo O (n * m), dove n è righe e m è colonne.
    • Risolve da destra a sinistra, segnando la direzione migliore da prendere da corrente a quello successivo.
    • le "linee" vengono gestite risolvendo la loro colonna, quindi indirizzandole se raggiungibili nella colonna successiva. Si risolvono memorizzando la direzione verso l'alto o verso il basso, con il costo della non linea eventualmente raggiungibile.
  • Tiene traccia, ma non stampa (nella versione da golf) il file indice di partenza di della soluzione migliore.

Ok, basta Jibba Jabba. Versione golfizzata:

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

Secondo la mia abitudine, github con il codice ungolfed .

Soluzione per la "prima" strada:

$ 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

Secondo esempio:

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

Campione di Brian Tuck:

$ 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

Esempio di "ubriaco" Brian:

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 | 544.956
697483176 5456034
09492201 | 6325551
395297030 | 3792913
 456363431 | 275.612
  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

Soluzione visualizzata:

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

Godere!

Modifica: ora sto solo mettendo in mostra (due strade si fondono! Può farcela?)

948384 | 4288324 324324 | 121323
120390 | 1232133 598732 | 123844
 293009 | 2394023 432099 | 230.943
 234882 | 2340909 843893 | 849.728
  238984 | 328498984328 | 230949
  509093 | 904389823787 | 439898
   438989 | 3489889344 | 438.984
   989789 | 7568945968 | 989.455
    568956 | 56985869 | 568.956
    988596 | 98569887 | 769.865
     769879 | 769078 | 678.977
     679856 | 568967 | 658.957
      988798 | 8776 | 987.979
      987878 | 9899 | 989.899
       999889 | | 989.899
       989999 | | 989.999
        989898 | | 998.999
        989999 | | 999999
         989998 || 899999
         989998 || 998.999

Soluzione:

$ 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

(bonus: percorso da ungolfed):

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

Dettagli sull'algoritmo

È stata richiesta una spiegazione più completa della tecnica di programmazione dinamica che ho utilizzato, quindi ecco:

Sto usando un metodo di soluzione mark-and-precompute. Ha un nome proprio, ma l'ho dimenticato da tempo; forse qualcun altro può offrirlo?

Algoritmo:

  • Partendo dalla colonna più a destra e procedendo a sinistra, calcola quanto segue su ciascuna cella della colonna:
    • La somma del movimento a costo più basso, definito come costo cella corrente + cella costo più basso raggiungibile nella colonna successiva
    • L'azione di movimento da intraprendere per ottenere questo costo più basso, come semplicemente un passaggio valido da questa cella a un'altra singola cella.
  • I tubi sono rinviati. Per risolvere una pipe, è necessario calcolare l'intera colonna, quindi non calcoliamo le pipe fino alla colonna successiva.
    • Quando si determina il costo più basso di una cella a sinistra di un tubo, prima calcoliamo la direzione migliore per spostarsi lungo il tubo: si risolverà sempre verso l'alto o verso il basso, quindi lo calcoliamo una volta.
    • Quindi memorizziamo, come con tutte le altre celle, il miglior costo (definito come il costo della cella che raggiungiamo viaggiando su o giù sul tubo) e la direzione da percorrere per raggiungerla.

Appunti:

Questo è tutto. Scansioniamo dall'alto verso il basso, da destra a sinistra, una volta; le uniche celle toccate (potenzialmente) più di una volta sono pipe, tuttavia, ogni pipe viene "risolta" solo una volta, mantenendoci all'interno della nostra finestra O (m * n).

Per gestire dimensioni di mappa "dispari", ho scelto di pre-scansionare e normalizzare lunghezze di righe riempiendole con caratteri null. I caratteri null valgono come "zero cost" si muove come pipe e spazi. Quindi, nella stampa della soluzione, interrompo la stampa dei costi o mi sposto quando viene raggiunto il bordo della strada normalizzata o viene raggiunto un carattere nullo.

Il bello di questo algoritmo è che è molto semplice, applica le stesse regole a ogni cellula, producendo una soluzione completa risolvendo i sotto-problemi O (m * n) e in termini di velocità è piuttosto veloce. Scambia la memoria, creando effettivamente due copie in memoria della carreggiata stradale, la prima per memorizzare i dati di "miglior costo" e la seconda per memorizzare i dati di "miglior spostamento" per cella; questo è tipico per la programmazione dinamica.


Potresti spiegare un po 'di più il tuo approccio alle linee? Ho anche tentato un approccio di programmazione dinamica (alquanto diverso), ma mi sono bloccato a capirli. Ho anche considerato un approccio incrementale (riga per riga) per gestire strade estremamente lunghe che non sono troppo larghe senza usare troppa memoria; sai se c'è un modo per farlo in meno di O (m ^ 2 * n) tempo?
dfeuer,

@dfeuer Di sicuro si tratta di compromessi. Nessuno degli approcci riga per riga che ho considerato erano in grado di gestire tutte le permutazioni dell'input senza soccombere al tempo O (m ^ n) ad un certo punto; questo è un problema colonna per colonna per costruzione (il movimento, in gran parte, va da sinistra a destra - una soluzione DP efficiente va da destra a sinistra). Potresti essere in grado di seguire un approccio O (m * n) risolvendo riga per riga con un semplice look-behind e uno sguardo differito, ma stai aumentando notevolmente la complessità senza probabilmente risparmiare molta memoria.
Programmatore:

Quello che stavo pensando era che se non sbaglio devi solo tenere traccia del percorso migliore finora e, per ogni quadrato nella riga elaborata più di recente, i percorsi più conosciuti dal bordo sinistro, al bordo destro e a ogni quadrato alla sua destra nella stessa riga. È sbagliato?
dfeuer,

1
Grazie! Puoi abbreviare il tuo codice una goccia definendo ccome -1>>>1.
dfeuer,

1
Sto prendendo di mira Haskell, il che renderà difficile competere a lungo, ma è di gran lunga quello che conosco meglio.
dfeuer,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.