Предсказать оползень


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

Попробуйте онлайн здесь


Снова
сорвали

снова @адицу?
Оптимизатор

Это не первый раз, когда кто-то избивает меня в 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Оператор проверяет последнее значение в стеке , не удаляя его. Если произошел оползень, значением является массив скал, который оценивается как true, потому что он не пустой. Если нет, последнее значение равно 0 (false).
Таким образом, в случае оползня цикл продолжается с массивом в стеке, в противном случае он заканчивается 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()и печатая результат в конце.
Згарб

Я не заметил этого решения и опубликовал свой немного худший 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 этой программы имеют только одну вкладку [т.е. один байт] отступа каждая.)

Принимает ввод на stdin, в hпервую очередь. Например:

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

Эта программа прошла через множество улучшений. Я редактировал этот ответ, чтобы объяснить некоторые из наиболее важных изменений, но он становился все длиннее. Вы можете проверить историю редактирования, если вам интересно.

объяснение

Сначала hи cчитаем из stdin. В Python 2 input()это эквивалентно eval(raw_input()), поэтому я спрашиваю запятую, разделяющую числа. input()возвращает кортеж целых чисел, преобразование не требуется.

Далее составляется список целых чисел. Это 2*hдолго. Первая половина hравна, а вторая половина равна 0. У меня нет никаких оснований доказывать, что этого достаточно, чтобы симулировать бесконечные hs слева и 0 справа. Я просто наткнулся на это, и он работает для всех тестовых случаев, поэтому, если кто-то сможет найти вход, он не работает, я с радостью его поменяю. В любом случае, этот список называется 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. Последняя строка программы использует каждый элемент las eв выражении h>e>0и суммирует результат. Получается число столбцов больше 0, но ниже, чем исходная высота обрыва, что является значением, которое запрашивает вопрос. Она распечатана, и программа завершается.


2
Не c-=cэквивалентно c=0?
Згарб

...Вау. спасибо за просмотр моей спиной, я должен был пойман , что, ха - ха
undergroundmonorail

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

@ Sp3000 Я совсем забыл о побитовой магии! Спасибо: D
подземный

3

Haskell, 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: спасибо за подсказки. Замена ()на это $- след и ошибка для меня.
Ними

3

Mathematica, 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);может потерять условие, не влияя на правильность, просто скорость.
Питер Тейлор,

@ Питер Тейлор. Благодарность!
Майк
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.