预测滑坡


22

滑坡

在此挑战中,您的工作是预测大规模滑坡造成的破坏程度。我们为其使用以下简化的二维模型,该模型以初始高度 h >= 0临界系数为参数 c > 0。您从高度为的悬崖开始h,并假定地形在其左右两侧完全无限平坦。对于h = 6,情况如下:

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

-是不可移动的基石,而且#是不稳定的土壤。如果相邻两列之间的高度差大于c,则会发生滑坡c左列的土壤的最高单位落到右列的下一c列,每列一列。图中最右边的非空列对于不稳定c = 2,因此触发了滑坡:

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

柱子仍然不稳定,导致第二次滑坡:

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

现在,其左侧的柱子变得不稳定,因此在那里触发了新的滑坡:

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

此后,悬崖再次稳定。这个模型的优点是滑坡的处理顺序无关紧要:最终结果是相同的。

任务

您的程序被赋予整数参数hc作为输入(顺序无关紧要,但是您必须在答案中指定它),并且它应该输出滑坡影响的总数。这意味着在所得的稳定悬崖中其高度严格在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

Answers:


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从当前索引元素中删除
      • 从当前索引添加1c数组的下一个元素
      • 使当前索引等于此新数组的长度
      • 这样可以确保我们先将石头稳定在当前索引的右侧
    • 否则,降低当前指数
  • 当我们点击最左边的索引时,我们将确保所有相邻索引的c差异小于或等于
  • 从数组中删除任何0h值并获取长度。

代码扩展

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?
Optimizer

这不是有人第一次在CJam击败我。这也不是第一次,尽管不确定是否曾经在直接竞争中做到过。
2015年

嘿:)有关算法的一切:)
Optimizer

4

果酱-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(假)。
因此,在发生山体滑坡的情况下,循环将继续在堆栈上放置数组,否则以在数组之后压入0结束。然后由下一个-运算符从数组中删除该0 。


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)

扩展版本:

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)

编辑:经过一些优化后,我通过break(节省1个字节)消除了尴尬的循环终止。也将幻灯片从基于切片更改为基于循环。


真好!您可以将方括号放在其中sum2个字节。同样,通常最好用Python定义一个完整的程序,然后输入h,c=input()并最终打印结果。
Zgarb 2015年

我没有注意到这个解决方案,而是张贴了一个稍差一点的D:哦,竞争很好。也许我可以看看是否可以从我的身上剃一些字节。顺便说一句,将您的比较结果翻转sum即可为您节省:sum(h>i>0for i in q)
地下

@undergroundmonorail我很努力,但我担心您的方法会更好:(。c=0节省了一个字节(我无法对您的回答发表评论)
。– Philipp

4

蟒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的markdown解释器将文字制表符转换为4个空格。该程序的第7行和第8行只有一个制表符[即一个字节]的缩进。)

h首先在stdin上输入。例如:

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

该程序已经进行了很多改进。我一直在编辑此答案,以解释一些更主要的编辑,但是它变得很长。如果您有兴趣,可以查看编辑历史记录。

说明

首先,hc从标准输入读取。在Python 2中,input()等效于eval(raw_input()),这就是为什么我要求用逗号分隔数字的原因。input()给定返回一个整数元组,无需转换。

接下来,创建一个整数列表。很2*h长 上半h部分为0,下半部分为0。我没有任何理由表明这足以模拟h左侧的infinite 以及右侧的0s。我只是偶然发现了它,并且它适用于所有测试用例,因此,如果有人可以找到输入,则该输入不起作用,因为我很乐意对其进行更改。无论如何,此列表被称为l,但它的另一个副本称为b

b的价值实际上并不重要,重要的是它的真实性。非空列表是真实的,唯一的方法b可以为空,如果if h为0,在这种情况下仍会打印正确的答案。在任何其他情况下,b必须诚实以确保我们进入while b:循环。但是,循环中发生的第一件事是将其设置b为0(一个假值)。在每次重复循环期间,b必须将其专门设置为“真”,否则循环将结束。

循环的其余部分是实际的模拟。这非常幼稚,本质上只是问题描述的代码翻译。如果任何元素l超过c大于所述一个跟随它,它是由相减c和下一个c元件已1添加到他们。(顺便说一句,这里使用的按位魔术只是一种较短的编写i+1+j方式。)进行这些转换时,b将其设置为1。第一次不进行转换时,b它将保持为0,并且循环终止。

任何true表达式的计算结果均为True,当您尝试对其进行数学运算时,True其计算结果为1。and False和0 也是如此。程序的最后一行使用表达式中las的每个元素并对结果求和。这将使列数大于0但小于原始悬崖高度,这是问题所要求的值。它已打印,程序退出。eh>e>0


2
c-=c等于c=0吗?
Zgarb 2015年

...哇。感谢您的支持,我应该已经注意到了,哈哈
Undergroundmonorail

1
i+1+j可以写成i-~j
Sp3000

@ Sp3000我完全忘记了位魔术!谢谢:d
undergroundmonorail

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 2015年

@Zgarb:感谢您的提示。更换()$的试错我。
nimi 2015年

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);可能会失去条件而不会影响正确性,只是速度。
彼得·泰勒

@彼得·泰勒 谢谢!
mike m
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.