Sagen Sie den Erdrutsch voraus

22

Erdrutsche

In dieser Herausforderung besteht Ihre Aufgabe darin, das Ausmaß der durch einen massiven Erdrutsch verursachten Schäden vorherzusagen. Wir verwenden das folgende vereinfachte zweidimensionale Modell, das durch eine Anfangshöhe h >= 0 und einen kritischen Koeffizienten parametrisiert wird c > 0. Sie beginnen mit einer hohen Klippe h, und es wird angenommen, dass das Gelände links und rechts davon unendlich flach ist. Für h = 6sieht die Situation so aus:

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

Das -sind unbewegliche Grundgesteine ​​und der #Boden ist instabil. Beträgt der Höhenunterschied zwischen zwei benachbarten Spalten mehr als c, kommt es zu einem Erdrutsch : Die obersten cBodeneinheiten der linken Spalte fallen zu den nächsten cSpalten rechts hinunter , eine zu jeder. Die am weitesten rechts stehende nicht leere Spalte in der Abbildung ist instabil c = 2, daher wird ein Erdrutsch ausgelöst:

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

Die Säule ist immer noch instabil, was einen zweiten Erdrutsch verursacht:

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

Jetzt ist die linke Spalte instabil geworden, sodass dort ein neuer Erdrutsch ausgelöst wird:

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

Danach ist die Klippe wieder stabil. Das Schöne an diesem Modell ist, dass die Reihenfolge, in der die Erdrutsche verarbeitet werden, keine Rolle spielt: Das Endergebnis ist dasselbe.

Die Aufgabe

Ihr Programm erhält die ganzzahligen Parameter hund cals Eingaben (die Reihenfolge spielt keine Rolle, aber Sie müssen sie in Ihrer Antwort angeben) und es sollte die Gesamtzahl der Spalten ausgeben , die vom Erdrutsch betroffen sind. Dies bedeutet die Anzahl der Spalten in der resultierenden stabilen Klippe, deren Höhe genau zwischen 0und liegt h. Im obigen Beispiel ist die korrekte Ausgabe 4.

Sie können ein vollständiges Programm oder eine Funktion schreiben. Die niedrigste Byteanzahl gewinnt, und Standardlücken sind nicht zulässig.

Testfälle

Diese sind im Format angegeben 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
Zgarb
quelle

Antworten:

5

CJam, 62 57 Bytes

Soweit ich sehen kann, ist dies ein völlig anderer Ansatz zur Implementierung der Lösung als die Antwort von aditsu.

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

Die Eingabe erfolgt in Form von h c

Beispiel:

80 5

Ausgabe:

28

Wie es funktioniert

Die Logik ist hier ziemlich einfach, mit ein paar Tricks, die zum Reduzieren der Codegröße verwendet werden.

  • Holen Sie sich h + 1( + 1für den h = 0Fall) Länge Array mit jedem Element, hdas die Klippe darstellen soll
  • Beginnen Sie mit der Iteration ab dem Index ganz rechts in diesem Array
    • Wenn sich die beiden Elemente aus dem aktuellen Index mehr als unterscheiden c
      • cAus dem aktuellen Indexelement entfernen
      • Hinzufügen 1zum nächsten cElemente der Anordnung aus dem aktuellen Index
      • Stellen Sie den aktuellen Index auf die Länge dieses neuen Arrays ein
      • Dies stellt sicher, dass wir die Steine ​​rechts vom aktuellen Index zuerst stabilisieren
    • Andernfalls verringern Sie den aktuellen Index
  • Wenn wir den Index ganz links treffen, stellen wir sicher, dass alle angrenzenden Indizes eine cDifferenz aufweisen, die kleiner oder gleich der Differenz ist
  • Entfernen Sie alle 0oder hWert aus dem Array und Länge erhalten.

Code-Erweiterung

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";

Probieren Sie es hier online aus

Optimierer
quelle
Nochmals vereitelt
@Aditsu wieder?
Optimierer
Es ist nicht das erste Mal, dass mich jemand bei CJam schlägt. Und nicht das erste Mal, dass Sie es tun, obwohl Sie nicht sicher sind, ob Sie es jemals in einem direkten Wettbewerb getan haben.
Aditsu
Heh :) Es dreht sich alles um den Algorithmus :)
Optimierer
4

CJam - 70

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

Versuchen Sie es unter http://cjam.aditsu.net/

Erläuterung:

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

Der hBediener prüft den letzten Wert auf dem Stapel, ohne ihn zu entfernen. Wenn ein Erdrutsch aufgetreten ist, ist der Wert das Cliff-Array, das als wahr ausgewertet wird, da es nicht leer ist. Wenn nicht, ist der letzte Wert 0 (falsch).
Im Falle eines Erdrutschs fährt die Schleife mit dem Array auf dem Stapel fort, andernfalls endet sie mit einer 0, die hinter dem Array steht. Diese 0 wird dann vom nächsten -Operator aus dem Array entfernt .

aditsu
quelle
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)

Erweiterte Version:

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)

Bearbeiten: Nach einigen Optimierungen habe ich die umständliche Schleifenbeendigung über break (spart 1 Byte) beseitigt. Außerdem wurde die Folie von scheibenbasiert auf schleifenbasiert geändert.

Philipp
quelle
Nett! Sie können die eckigen Klammern sumfür 2 Bytes nach innen setzen . Außerdem ist es normalerweise besser, ein vollständiges Programm in Python zu definieren, Eingaben mit aufzunehmen h,c=input()und das Ergebnis am Ende auszudrucken.
Zgarb,
Ich habe diese Lösung nicht bemerkt und mein etwas schlechteres D gepostet: Naja, die Konkurrenz ist nett. Vielleicht werde ich mal sehen, ob ich ein paar Bytes von meinen rasieren kann. By the way, Ihre Vergleiche in Ihren Spiegeln sumkann sparen Sie ein: sum(h>i>0for i in q).
Undergroundmonorail
@undergroundmonorail Ich habe mich sehr bemüht, aber ich fürchte, Ihr Ansatz ist einfach überlegen :(. c=0Speichert ein Byte (ich kann Ihre Antwort nicht kommentieren).
Philipp
4

Python 2 - 194 158 Bytes

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)

(Beachten Sie, dass der Markdown-Interpreter von SE Literal-Tabulatoren in vier Leerzeichen umwandelt. Die Zeilen 7 und 8 dieses Programms enthalten jeweils nur einen Tabulator (dh ein Byte) mit Einrückung.)

Übernimmt zuerst die Eingabe für stdin h. Beispielsweise:

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

Dieses Programm hat viele Verbesserungen durchgemacht. Ich hatte diese Antwort überarbeitet, um einige der wichtigsten Änderungen zu erklären, aber es wurde ein bisschen lang. Sie können den Bearbeitungsverlauf überprüfen, wenn Sie neugierig sind.

Erläuterung

Zuerst hund cwerden von stdin gelesen. In Python 2 input()entspricht eval(raw_input()), weshalb ich nach einem Komma frage, das die Zahlen trennt. input()Gibt ein Tupel Ints zurück, ohne dass eine Konvertierung erforderlich ist.

Als nächstes wird eine Liste von ganzen Zahlen erstellt. Es ist 2*hlang Die erste Hälfte ist hund die zweite Hälfte ist 0. Ich habe keinen Grund zu zeigen, dass dies ausreicht, um unendliche hs links und 0s rechts zu simulieren . Ich bin nur ein bisschen hineingestolpert und es funktioniert für alle Testfälle. Wenn also jemand eine Eingabe findet, funktioniert sie nicht, dann ändere ich sie gerne. Wie auch immer, diese Liste wird aufgerufen l, aber eine andere Kopie davon wird aufgerufen b.

bDer Wert von ist eigentlich egal, alles was zählt ist, dass es wahr ist. Eine nicht leere Liste ist wahr und der einzige Weg b, hier leer zu sein, ist, wenn h0 ist. In diesem Fall wird die richtige Antwort immer noch gedruckt. In jedem anderen Fall bmuss wahr sein, um sicherzustellen, dass wir in die while b:Schleife eintreten . Das erste, was in der Schleife passiert, ist das Setzen bauf 0, einen falschen Wert. Während jeder Wiederholung bmuss die Schleife gezielt auf eine Wahrheit zurückgesetzt werden, sonst endet die Schleife.

Der Rest der Schleife ist die eigentliche Simulation. Es ist sehr naiv, im Wesentlichen nur eine Code-Übersetzung der Problembeschreibung. Wenn eines der Elemente von lmehr als cdas folgende Element ist , wird es um subtrahiert cund den nächsten cElementen wird 1 hinzugefügt. (Die hier verwendete bitweise Magie ist im Übrigen nur eine kürzere Schreibweise i+1+j.) Wird beim Durchführen dieser Transformationen bauf 1 gesetzt. Wenn zum ersten Mal keine Transformationen durchgeführt werden, bbleibt der Wert 0, und die Schleife wird beendet.

Jeder wahre Ausdruck wird zu 1 ausgewertet True, und wenn Sie versuchen, mit ihm zu rechnen, wird Trueer zu 1 ausgewertet. Dasselbe gilt für Falseund 0. Die letzte Zeile des Programms verwendet jedes Element von lwie eim Ausdruck h>e>0und summiert das Ergebnis. Dadurch wird die Anzahl der Spalten größer als 0, aber kleiner als die ursprüngliche Klippenhöhe. Dies ist der Wert, nach dem die Frage fragt. Es wird gedruckt und das Programm wird beendet.

untergrundbahn
quelle
2
Ist nicht c-=cgleichbedeutend mit c=0?
Zgarb,
...Wow. danke fürs aufpassen, ich hätte das fangen sollen, haha
undergroundmonorail
1
i+1+jkann geschrieben werden alsi-~j
Sp3000
@ Sp3000 Ich habe die bitweise Magie total vergessen! Danke: D
undergroundmonorail
3

Haskell, 163 156 151 Bytes

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)

Verwendung: h#czB 6#2welche Ausgänge 4.

So funktioniert es: Die Helferfunktion smacht einen einzelnen Erdrutsch. Wiederholt anwenden, sbis sich die Ausgabe nicht mehr ändert. Zählen Sie die betroffenen Elemente.

Es wurde die Funktion " Anwenden , bis sich die Ausgabe nicht ändert" (dh until=<<((==)=<<)) bei Stackoverflow gefunden .

nimi
quelle
Sie können einige Bytes speichern, indem Sie fals infix ( h#c=...) definieren und die whereKlausel in dieselbe Zeile verschieben. Außerdem müssen noch einige Klammern verwendet werden $, obwohl ich nicht sicher bin, wie viele ...
Zgarb
@Zgarb: danke für die hinweise. Das Ersetzen ()durch $ist für mich eine Spur und ein Irrtum.
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]&

Verwendung:

f[c, h]

Beispiel:

f[5, 80]

28

Alephalpha
quelle
2

C # 303 295

Es klappt!

Aber es ist ein ....

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

Ich muss neue sprache finden;)

Ich werde diese CJam-Sache überprüfen ...

Verbessert:

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;}
mike m
quelle
1
Sie können dies noch ein wenig optimieren. int z=i;int y=i-1;könnte sein int z=i,y=i-1;. Die forSchleifen machen mit ihren Indizes keine komplizierten Dinge, so for(int i=s.Count-1;i>0;i--)könnte es zB sein for(int i=s.Count;--i>0;). 1<0ist eine kürzere Schreibweise false. Ich vermute, das if(s[s.Count-1]>0)s.Add(0);könnte den Zustand verlieren, ohne die Richtigkeit zu beeinträchtigen, nur die Geschwindigkeit.
Peter Taylor
@ Peter Taylor. Vielen Dank!
mike m