Прогнозуйте зсув


22

Зсуви

У цьому виклику ваше завдання полягає в тому, щоб передбачити ступінь збитків, спричинених масовим зсувом. Для цього ми використовуємо наступну спрощену двовимірну модель, параметризовану за початковою висотою h >= 0 та критичним коефіцієнтом c > 0 . Ви починаєте зі скелі висоти h, і передбачається, що місцевість повністю рівна нескінченно ліворуч і праворуч від неї. Бо h = 6ситуація виглядає приблизно так:

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

Вони -є нерухомими породами, а #нестабільний ґрунт. Якщо різниця висот між двома сусідніми стовпчиками більша c, виникає зсув : верхні cодиниці ґрунту з лівого стовпчика опускаються до наступних cстовпців праворуч, по одному до кожного. Крайній правий стовпчик на рисунку нестабільний c = 2, тому запускається зсув:

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

Стовпчик ще нестабільний, що спричиняє другий зсув:

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

Тепер стовпчик ліворуч став нестабільним, тому там запускається новий зсув:

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

Після цього скеля знову стабільна. Приємно в цій моделі те, що порядок обробки зсувів не має значення: кінцевий результат той самий.

Завдання

Вашій програмі задаються цілі параметри hі cяк вхідні дані (порядок не має значення, але ви повинні вказати це у своїй відповіді), і вона повинна виводити загальну кількість стовпців , на які впливає зсув. Це означає кількість стовпців у отриманій стійкій скелі, висота якої суворо між 0і h. У наведеному вище прикладі правильний вихід 4.

Ви можете написати повну програму або функцію. Виграє найменший кількість байтів, а стандартні лазівки заборонені.

Випробування

Вони наведені у форматі 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

Відповіді:


5

CJam, 62 57 байт

Наскільки я бачу, це зовсім інший підхід до реалізації рішення з відповіді aditsu.

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

Введення йде у формі h c

Приклад:

80 5

Вихід:

28

Як це працює

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

  • Отримайте h + 1( + 1для h = 0випадку) масив довжини, причому кожен елемент hповинен представляти скелю
  • Почніть ітерацію з самого правого індексу цього масиву
    • Якщо два елементи з поточного індексу мають різні більше, ніж c
      • Видалити cз поточного елемента індексу
      • Додати 1до наступних cелементів масиву з поточного індексу
      • Зробіть поточний індекс рівним довжині цього нового масиву
      • Це гарантує, що ми спочатку стабілізуємо камені праворуч від поточного покажчика
    • інше, зменшити поточний індекс
  • Коли ми потрапляємо в лівий індекс, ми переконуємося, що всі сусідні індекси мають cрізницю меншу або рівну
  • Видаліть будь-яке значення 0або hзначення з масиву і отримайте довжину.

Розширення коду

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

Спробуйте його онлайн тут


Знову
згорнутий

@aditsu знову?
Оптимізатор

Це не перший раз, коли мене хтось б’є в CJam. І не вперше ви це робите, хоча не впевнений, чи раніше це робили в прямій конкуренції.
aditsu

Хе :) Все про алгоритм :)
Оптимізатор

4

CJam - 70

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

Спробуйте це на http://cjam.aditsu.net/

Пояснення:

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

hОператор перевіряє останнє значення в стеку , але залишити його. Якщо стався зсув, значення - це масив скелі, який оцінюється як істинне, оскільки воно не порожнє. Якщо ні, то останнє значення дорівнює 0 (хибне).
Тож у випадку зсуву петля продовжується з масивом на стеку, інакше закінчується 0, натиснутою після масиву. Потім 0 ​​видаляється з масиву наступним -оператором.


4

Пітон, 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)

Розширена версія:

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)

Редагувати: Після деякої оптимізації я усунув незручне завершення циклу за допомогою перерви (економить 1 байт). Також змінено слайд з фрагмента на основі циклу.


Приємно! Ви можете опустити квадратні дужки всередину sumна 2 байти. Крім того, зазвичай краще визначити повну програму в Python, взявши введення h,c=input()та надрукувавши результат в кінці.
Zgarb

Я не помітив цього рішення і розмістив своє трохи гірше: D: Ну добре, конкуренція хороша. Можливо, я побачу, чи зможу я поголити кілька байтів з моїх. До речі, гортати ваші порівняння в вашому sumможе врятувати вас один: sum(h>i>0for i in q).
підземниймонорельс

@undergroundmonorail Я дуже старався, але боюся, що ваш підхід просто перевершує :(. c=0економить байт (я не можу коментувати вашу відповідь).
Філіп

4

Python 2 - 194 158 байт

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)

(Зверніть увагу, що інтерпретатор розмітки SE перетворює буквальні вкладки в 4 пробіли. У рядках 7 і 8 цієї програми є лише одна вкладка [тобто один байт] відступу кожна.)

hСпочатку бере вкладку на stdin . Наприклад:

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

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

Пояснення

По-перше, hі cчитаються з stdin. У Python 2 input()рівнозначно eval(raw_input()), тому я прошу коми, що розділяють числа. input()повертає кордону вкладок, не потрібна конверсія.

Далі складається список цілих чисел. Це 2*hдовго. Перша половина, hа друга половина - 0. У мене немає жодних міркувань, щоб показати, що цього достатньо для імітації нескінченних hs вліво та 0s вправо. Я просто натрапив на нього, і він працює для всіх тестових випадків, тому якщо хтось може знайти вхід, він не працює, я з радістю його зміню. У будь-якому випадку цей список називається l, але називається інша його копія b.

bЦінність насправді не має значення. Важливо лише те, що це правда. Непорожній список є правдоподібним, і єдиний спосіб bможе бути порожнім тут, якщо hце 0, і тоді правильна відповідь все ж надрукована. У будь-якому іншому випадку, bвін повинен бути правдоподібним, щоб переконатися, що ми входимо в while b:цикл. Однак перше, що відбувається в циклі, - bце 0, значення фальси. Під час кожного повторення циклу bнеобхідно спеціально повернутись на вершину, або цикл закінчиться.

Решта циклу - власне моделювання. Це дуже наївно, по суті це просто переклад коду опису проблеми. Якщо будь-який елемент у розмірі lбільше, ніж cтой, що слідує за ним, він віднімається cі наступні cелементи додають до них 1. (Доречна магія, що використовується тут, - це лише коротший спосіб написання i+1+j, до речі.) Під час здійснення цих перетворень bвстановлено значення 1. Перший раз, коли не буде здійснено перетворень, bзалишиться 0 і цикл припиняється.

Будь-який істинний вираз оцінюється до True, а при спробі займатися математикою Trueвін оцінює до 1. Те ​​саме стосується Falseі 0. В останньому рядку програми використовується кожен елемент, lяк eу виразі, h>e>0і підсумовується результат. Це отримує кількість стовпців більше 0, але нижче, ніж початкова висота скелі, що є значенням, яке запитує. Він надрукований і програма виходить.


2
Це не c-=cрівнозначно c=0?
Zgarb

...Ого. дякую, що стежив за моєю спиною, я повинен був би це спіймати, ха-ха
підземний

1
i+1+jможна записати якi-~j
Sp3000

@ Sp3000 Я зовсім забув про побітну магію! Спасибі: D
підземний

3

Хаскелл, 163 156 151 байт

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)

Використання:, h#cнаприклад, 6#2які виходи 4.

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

Знайдено функцію "застосувати, поки вихід не зміниться" (тобто until=<<((==)=<<)) на Stackoverflow .


Ви можете зберегти пару байтів, визначившись fяк infix ( h#c=...) і перемістивши whereпункт в той самий рядок. Також є ще дужки, які потрібно пролити $, хоча я не впевнений, скільки ...
Zgarb

@ Zgarb: дякую за підказки. Заміна ()з $є слід і помилка для мене.
німі

3

Математика, 108 104 100 97 95

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

Використання:

f[c, h]

Приклад:

f[5, 80]

28


2

C # 303 295

Це працює!

Але це….

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

Я повинен знайти нову мову;)

Я перевірю цю річ CJam ...

Поліпшено:

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
Ви все ще можете трохи оптимізувати це. int z=i;int y=i-1;могло бути int z=i,y=i-1;. В forпетлі не робити складні речі з їх індексами, так , наприклад , for(int i=s.Count-1;i>0;i--)може бути for(int i=s.Count;--i>0;). 1<0- це коротший спосіб написання false. Я підозрюю, що if(s[s.Count-1]>0)s.Add(0);міг втратити стан, не впливаючи на правильність, просто швидкість.
Пітер Тейлор

@ Петер Тейлор. Спасибі!
mike m
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.