Predire la frana


22

frane

In questa sfida, il tuo compito è prevedere l'entità del danno causato da una grande frana. Per questo utilizziamo il seguente modello bidimensionale semplificato, parametrizzato da un'altezza iniziale h >= 0 e un coefficiente critico c > 0 . Inizi con una scogliera di altezza he si presume che il terreno sia completamente piatto all'infinito a sinistra e a destra di esso. Per h = 6, la situazione si presenta così:

##########
##########
##########
##########
##########
##########
-----------------------

La -sono inamovibile roccia, e #sono terreno instabile. Se la differenza di altezza tra due colonne vicine è maggiore di c, si verifica una frana : le cunità superiori di terreno dalla colonna di sinistra cadono verso le ccolonne successive a destra, una per ciascuna. La colonna non vuota più a destra nella figura è instabile c = 2, quindi viene attivata una frana:

#########
#########
##########
##########
##########
############
-----------------------

La colonna è ancora instabile, il che provoca una seconda frana:

#########
#########
#########
#########
############
############
-----------------------

Ora, la colonna alla sua sinistra è diventata instabile, quindi una nuova frana viene innescata lì:

########
########
#########
###########
############
############
-----------------------

Dopo questo, la scogliera è di nuovo stabile. La cosa bella di questo modello è che l'ordine in cui vengono elaborate le frane non ha importanza: il risultato finale è lo stesso.

L'obiettivo

Al programma vengono forniti i parametri interi he ccome input (l'ordine non ha importanza, ma è necessario specificarlo nella risposta) e dovrebbe generare il numero totale di colonne interessate dalla frana. Ciò significa che il numero di colonne nella scogliera stabile risultante la cui altezza è strettamente tra 0e h. Nell'esempio sopra, l'output corretto è 4.

È possibile scrivere un programma completo o una funzione. Vince il conteggio di byte più basso e non sono consentite scappatoie standard.

Casi test

Questi sono indicati nel formato h c -> output.

0  2  -> 0
2  3  -> 0
6  2  -> 4
6  6  -> 0
10 1  -> 10
15 1  -> 14
15 2  -> 11
15 3  -> 6
40 5  -> 16
80 5  -> 28
80 10 -> 17

Risposte:


5

CJam, 62 57 byte

Per quanto posso vedere, questo è un approccio completamente diverso per implementare la soluzione dalla risposta di Aditsu.

q~:C;:HaH)*H){(:I\_@>2<:-C>{I0a*C~)+C1a*+]z1fb_,}I?}h-H-,

L'input ha la forma di h c

Esempio:

80 5

Produzione:

28

Come funziona

La logica è piuttosto semplice qui con alcuni trucchi usati per ridurre la dimensione del codice.

  • Ottieni h + 1( + 1per h = 0caso) un array di lunghezza con ogni elemento che hrappresenta la scogliera
  • Inizia iterando dall'indice più a destra di questo array
    • Se i due elementi dall'indice corrente hanno più di c
      • Rimuovi cdall'elemento indice corrente
      • Aggiungi 1agli celementi successivi dell'array dall'indice corrente
      • Rendi l'indice corrente uguale alla lunghezza di questo nuovo array
      • Questo ci assicura di stabilizzare prima le pietre a destra dell'indice corrente
    • altrimenti, ridurre l'indice corrente
  • Quando abbiamo raggiunto il massimo indice di sinistra, stiamo facendo in modo che tutti gli indici adiacenti hanno meno o uguale a cdifferenza
  • Rimuovere qualsiasi 0o hvalore dall'array e ottenere lunghezza.

Espansione del codice

q~:C;:HaH)*H){(:I\_@>2<:-C>{I0a*C~)+C1a*+]z1fb_,}I?}h-H-,
q~:C;:HaH)*H)
q~:C;:H                  "Read the input, evaluate it, store height in H and coeff. in C";
       aH)*              "Wrap the height number in an array and repeat it H + 1 times";
           H)            "Put H+1 on stack, representing the current index of iteration";
{(:I\_@>2<:-C>{I0a*C~)+C1a*+]z1fb_,}I?}h
(:I\_@>2<:-C>
(:I                      "Decrement the current index and store it in I";
   \_                    "Swap to put array on top and make 1 copy";
     @>2<                "Get the two elements starting from Ith index";
         :-              "Get the difference. The best part of this approach is that";
                         "For the right most index, where there is only element, it";
                         "returns the element itself, which is the expected difference";
           C>            "Check if difference is greater than C";
{I0a*C~)+C1a*+]z1fb_,}   "This block will be executed when the difference is more than C";
 I0a*                    "Get an array of I length and all elements 0";
     C~)+                "Get -C value and append it to the above array";
         C1a*+           "Get C length array of 1s and concat with the above array";
              ]          "Wrap the two arrays, the cliff and the above one in an array";
               z1fb      "Transpose to get number pairs and add those pairs. For example";
                         "If we are at the right most index with H = 80 and C = 5,";
                         "The right section of the cliff looks like:";
                         "[ ... 80 80 80 80 80] and the array created in above step";
                         "looks like [ ... 0 0 0 0 -5 1 1 1 1 1]. After z, we have:";
                         "[ ... [80 0] [80 0] [80 0] [80 0] [80 -5] [1] [1] [1] [1] [1]]";
                         "After 1fb we get [ ... 80 80 80 80 75 1 1 1 1 1]";
                   _,    "Take a copy of the above resultant array and take its length";
I?                       "If difference was not greater than C, put I on stack";
                         "Now we either have the decremented index or new array length";
                         "on stack."
{ ... }h                 "This is a do while loop which makes sure that we iterate to";
                         "the left of the array. This loops runs till the top stack";
                         "element is 0 while not popping the top element";
        -H-,             "After the loop, we have the final cliff array and 0 on stack";
                         "Remove any 0 elements from the array, then remove any H";
                         "elements from the array and then take length to get the";
                         "number of columns which were modified";

Provalo online qui


Sventato di nuovo: p Ben fatto :)
aditsu,

@aditsu di nuovo?
Ottimizzatore

Non è la prima volta che qualcuno mi picchia al CJam. E non la prima volta che lo fai, anche se non sono sicuro di averlo mai fatto prima in competizione diretta.
aditsu,

Heh :) È tutto sull'algoritmo :)
Ottimizzatore

4

CJam - 70

q~:C;:H0]H*$W%{[__W<\1>]z{~-}%{C>}#):I{I(_2$=C-tC,{I+_2$=)t}/}0?}h-H-,

Provalo su http://cjam.aditsu.net/

Spiegazione:

q~                    read and evaluate the input
:C;                   store the 2nd number in C and remove
:H                    store the first number in H
0]H*                  make an array [H 0] and repeat it H times
$W%                   sort and reverse, obtaining [(H H's) (H 0's)] (initial cliff)
{                     loop...
    [__W<\1>]         make an array with the cliff without the first column
                      and the cliff without the last column
    z{~-}%            subtract the 2 arrays to get the height differences
    {C>}#             find the index of the first height diff. greater than C
    ):I               increment and store in I
    {                 if the value is non-zero (i.e. landslide occurring)
        I(_2$=C-t     subtract C from the corresponding column height
        C,            make an array [0 1 ... C-1]
        {             for each of those numbers
            I+        add I, obtaining a column index where some soil falls
            _2$=)t    increment the column height
        }/            end loop
    }0?               else break outer loop; end if
}h                    ...while the condition is true
-H-                   remove all 0 and H from the final stable cliff
,                     count the remaining columns

L' hoperatore controlla l'ultimo valore nello stack senza rimuoverlo. Se si è verificata una frana, il valore è l'array cliff, che restituisce true perché non è vuoto. In caso contrario, l'ultimo valore è 0 (falso).
Quindi, in caso di frana, il ciclo continua con l'array nello stack, altrimenti termina con uno 0 premuto dopo l'array. Quel 0 viene quindi rimosso dall'array dall'operatore successivo -.


4

Python, 200 190 174

h,c=input();q=[h]*h+[0]*h
try:
 while 1:
    d=[b-a for a,b in zip(q[1:],q)];g=max(d);a=d.index(g)
    for i in range(c):q[a+1+i]+=1/(g>c);q[a]-=1
except:print sum(h>i>0for i in q)

Versione estesa:

h, c = input()
# Initialize the heights
q = [h]*h + [0]*h
try:
    while 1:
        # Difference between the heights
        d = [b-a for a,b in zip(q[1:],q)]
        # It may error here, when h == 0, but thats okay
        g = max(d)
        a = d.index(g)
        for i in range(c):
            # This is the termination condition, when g <= c
            q[a+1+i] += 1 / (g>c)
            # Save the newline; also move this line to after termination
            q[a] -= 1
except:
    # Count all heights that have changed
    print sum(h > i > 0 for i in q)

Modifica: dopo un po 'di ottimizzazione, ho eliminato la terminazione del loop scomodo tramite interruzione (salva 1 byte). Modificata anche la diapositiva da slice basata su loop based.


Bello! È possibile rilasciare le parentesi quadre all'interno sumper 2 byte. Inoltre, di solito è meglio definire un programma completo in Python, prendendo input h,c=input()e stampando il risultato alla fine.
Zgarb,

Non ho notato questa soluzione e ho pubblicato la mia leggermente peggiore D: Oh beh, la concorrenza è bella. Forse vedrò se riesco a radere alcuni byte dal mio. Tra l'altro, lanciando i confronti nel vostro sumRiuscirai a salvare uno: sum(h>i>0for i in q).
undergroundmonorail,

@undergroundmonorail Ho provato duramente, ma temo che il tuo approccio sia semplicemente superiore :(. c=0salva un byte (non posso commentare la tua risposta).
Philipp

4

Python 2 - 194 158 byte

h,c=input()
b=l=[h]*h+[0]*h
while b:
 b=0
 for i in range(len(l)-1):
  if l[i]-l[i+1]>c:
    for j in range(c):l[i-~j]+=1
    l[i]-=c;b=1
print sum(h>e>0for e in l)

(Si noti che l'interprete markdown di SE converte le tabulazioni letterali in 4 spazi. Le righe 7 e 8 di questo programma hanno solo una singola scheda [cioè un byte] di rientro ciascuna.)

Accetta hprima lo stdin . Per esempio:

$ ./landslide.py <<< '6, 2'
4

Questo programma ha subito molti miglioramenti. Avevo modificato questa risposta per spiegare alcune delle modifiche più importanti, ma stava diventando un po 'lungo. Puoi controllare la cronologia delle modifiche se sei curioso.

Spiegazione

Innanzitutto, he cvengono letti dallo stdin. In Python 2, input()equivale a eval(raw_input()), motivo per cui chiedo una virgola che separa i numeri. input()restituisce una tupla di ints, nessuna conversione richiesta.

Successivamente, viene creato un elenco di numeri interi. È 2*hlungo. La prima metà è he la seconda metà sono 0. Non ho alcun ragionamento per dimostrare che questo è sufficiente per simulare infiniti hs a sinistra e 0s a destra. In qualche modo mi sono imbattuto in esso e funziona per tutti i casi di test, quindi se qualcuno riesce a trovare input non funziona per lo cambierò volentieri. Comunque, questo elenco viene chiamato l, ma viene chiamata un'altra copia di esso b.

bIl valore in realtà non importa, tutto ciò che conta è che sia vero. Un elenco non vuoto è vero e l'unico modo che bpuò essere vuoto qui è se hè 0, nel qual caso viene comunque stampata la risposta corretta. In ogni altro caso, bdeve essere sincero per assicurarci di entrare nel while b:ciclo. Tuttavia, la prima cosa che accade nel loop è l'impostazione bsu 0, un valore di falso. Durante ogni ripetizione del loop bdeve essere specificamente riportato a uno vero o il loop finirà.

Il resto del loop è la simulazione reale. È molto ingenuo, essenzialmente essendo solo una traduzione in codice della descrizione del problema. Se un elemento di lè più che cmaggiore di quello che lo segue, viene sottratto da ce gli celementi successivi ne hanno 1 aggiunto. (A proposito i+1+j, la magia bit a bit usata qui è solo un modo più breve di scrivere .) Mentre si effettuano queste trasformazioni, bè impostato su 1. La prima volta che non vengono eseguite trasformazioni, brimarrà 0 e il ciclo termina.

Qualsiasi espressione vera viene valutata Truee quando si tenta di eseguire la matematica su di Trueessa , si ottiene 1. Lo stesso vale per Falsee 0. L'ultima riga del programma utilizza ogni elemento di lcome enell'espressione h>e>0e somma il risultato. Questo ottiene il numero di colonne maggiore di 0 ma inferiore all'altezza originale della scogliera, che è il valore richiesto dalla domanda. Viene stampato e il programma esce.


2
Non è c-=cequivalente a c=0?
Zgarb,

...Wow. grazie per avermi guardato le spalle, avrei dovuto prenderlo, haha
undergroundmonorail,

1
i+1+jpuò essere scritto comei-~j
Sp3000 l'

@ Sp3000 Mi ero completamente dimenticato della magia bit a bit! Grazie: D
undergroundmonorail,

3

Haskell, 163 156 151 byte

h#c=sum[1|e<-(until=<<((==)=<<))s$r h++r 0,e`mod`h/=0]where r=replicate$h+1;s w@(x:y:z)|x==0=w|x>c+y=x-c:map(+1)(take c(y:z))++drop c(y:z)|1<2=x:s(y:z)

Utilizzo: h#cad es . 6#2Quali uscite 4.

Come funziona: la funzione helper sesegue una singola frana. Applicare ripetutamente sfino a quando l'output non cambia più. Conta gli elementi interessati.

Trovata la funzione "applica fino a quando l'output non cambia" (ad es. until=<<((==)=<<)) Su Stackoverflow .


È possibile salvare un paio di byte definendo fcome infix ( h#c=...) e spostando la whereclausola sulla stessa riga. Inoltre, ci sono ancora alcune parentesi da perdere $, anche se non sono sicuro di quante ...
Zgarb

@Zgarb: grazie per i suggerimenti. La sostituzione ()con $è trail ed errore per me.
nimi,

3

Mathematica, 108 104 100 97 95

f=Max@#-Min@#&[0Range@#2//.{x___,k:##..&[a_,{#}],a_,y___}:>Sort@{x,##&@@({k}-1),a+#,y}/.{}->0]&

Uso:

f[c, h]

Esempio:

f[5, 80]

28


2

C # 303 295

Funziona!

Ma è un ....

int q(int n,int c){var s=Enumerable.Repeat(n,n).ToList();s.Add(0);var d=new HashSet<int>();var g=true;while(g){g=false;for(int i=s.Count-1;i>0;i--){int z=i;int y=i-1;if((s[y]-s[z])>c){s[y]-=c;d.Add(y);g=true;for(int j=1;j<=c;j++){s[y+j]++;d.Add(y+j);if(s[s.Count-1]>0)s.Add(0);}break;}}}return d.Count;}

Devo trovare una nuova lingua;)

Controllerò questa cosa di CJam ...

migliorata:

int q(int n,int c){var s=Enumerable.Repeat(n,n).ToList();s.Add(0);var d=new HashSet<int>();var g=1>0;while(g){g=1<0;for(int i=s.Count-1;i>0;i--){int z=i,y=i-1;if((s[y]-s[z])>c){s[y]-=c;d.Add(y);g=1>0;for(int j=1;j<=c;j++){s[y+j]++;d.Add(y+j);if(s[s.Count-1]>0)s.Add(0);}break;}}}return d.Count;}

1
Puoi ancora ottimizzarlo un po '. int z=i;int y=i-1;potrebbe essere int z=i,y=i-1;. I forloop non fanno cose complicate con i loro indici, quindi ad esempio for(int i=s.Count-1;i>0;i--)potrebbero esserlofor(int i=s.Count;--i>0;) . 1<0è un modo più breve di scrivere false. Ho il sospetto che if(s[s.Count-1]>0)s.Add(0);potrebbe perdere la condizione senza compromettere la correttezza, solo la velocità.
Peter Taylor,

@Peter Taylor. Grazie!
mike m,
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.