鸡是怎么过马路的?


16

咯咯咯咯咯咯。没有人知道为什么鸡肉过马路,也许另一边有一只漂亮的公鸡。但是我们可以弄清楚如何做。编写一个程序,从左到右,穿过这个(或任何)“道路”。

1356 | 1738
3822 | 1424
3527   3718
9809 | 5926
0261 | 1947
7188   4717
6624 | 9836
4055 | 9164
2636   4927
5926 | 1964
3144 | 8254

您的程序“越过”它,从左到右移动。您可以从最喜欢的列的任何数字开始。从那里,您可以移动到右侧的任何相邻字符。如果从左上角的1​​开始,则可以转到3或8。将转到的每个数字(包括起始数字)都添加到总和中。空格不会增加您的总和。“ |” 迫使您向上或向下移动,而不是向右移动。(您不能在这个角色上前进)您的目标是以最小的总和到达对方。您的程序必须在最后打印出总和,并且它必须能够解决任何问题。最好也可以有一条道路的输入,但这不是必需的。您的程序必须同时打印路径和总和。最少的代码字节获胜。

为了清楚起见,除非在垂直条上,否则可以沿对角线移动。当您在垂直栏上时,只能上下移动。

为了更清晰地说明道路,基本上是一串遵循字符规则的文本字符串(或者是列或行的数组,您应该更喜欢这样考虑),但是这些字符中没有任何内容马路。可以有任何数字,空格,竖线(“ |”)或换行符。如果像一条醉汉那样铺了一条路,就像ProgrammerDan的回答一样,那条路仍然是有效的,您的程序必须能够解决这条路。如果无法到达另一侧,则不认为这条路是可行的(例如,没有任何一条路可以走出一条直线)。

您的程序无需确定道路是否无效。

密钥:
任意数字-将数字加到您的总和中,继续前进。
空格-继续前进,您的总和不会增加任何东西。
“ |” -向上或向下移动,您的总和没有增加。

编辑:建议的示例解决方案。我不能做一个非常大的东西,我不能上IDE来为我的ATM解决它。

走这条小路:

9191 | 8282
1919 | 2727
5555   5555

该解决方案将是1、1、1、1,空格,分隔线,分隔线,空格,空格,2、2、2、2的路径,总共为12。

编辑#2:由Geobits和人民计划确定的第一个问题的解决方案是0,2,0,1,,,,,1,4,1,4,总和为13。


4
您能否包括至少一个具有正确解决方案的测试用例?另外,可以|连续超过三个吗?
Martin Ender

1
@timmy,只要它向前移动,就可以对角移动。可以通过几个对角线移动来触摸它。
CaffeineToCode

3
@ mbomb007如果从左上角开始。由于您可以从左列中的任何一个开始,因此可以获得0,2,0,1, , , ,1,4,1,4 -> 13
Geobits,2015年

1
是的,它确实。您只能在栏上向上或向下移动,因此只能通过空格离开它们。
CaffeineToCode 2015年

1
对于输出,仅成本就足够了,还是需要输出整个路径?
ProgrammerDan

Answers:


3

Pyth,168个 143 141字节[现在醉路兼容]

我的测试用例可以工作,但是由于我的误解,它在最初的示例中无法正常工作。我正在修复它。

现在正在为原始示例和醉酒的道路工作

有些真的 略少丑陋的代码:

=Z.dC,++\ `MUT\|++0UT=^T5Ltu+G]?&qeeG\|<heGhH+eGeHHtb,0hbKhohNum++hed@ZhhdtedC,H_y_y.b+N]YmhohNd.:++TGT3HCm.[d\ lh.MlZ.z.z*hl.z]]0j\,t.sK\ hK

在这里测试

我在10 + 9 x 40的道路上进行了测试。

6417443208|153287613
8540978161|726772300
7294922506 263609552
0341937695 498453099
9417989188 370992778
2952186385|750207767
7049868670 756968872
1961508589|379453595
0670474005 070712970
4817414691|670379248
0297779413|980515509
6637598208 090265179
6872950638 767270459
7375626432 439957105
1387683792|544956696
6974831376 545603884
0949220671|632555651
3952970630|379291361
0456363431|275612955
2973230054|830527885
5328382365|989887310
4034587060 614168216
4487052014|969272974
5015479667 744253705
5756698090|621187161
9444814561|169429694
7697999461|477558331
3822442188 206942845
2787118311|141642208
2669534759 308252645
6121516963|554616321
5509428225|681372307
6619817314|310054531
1759758306 453053985
9356970729|868811209
4208830142 806643228
0898841529|102183632
9692682718|103744380
5839709581|790845206
7264919369|982096148

请注意,使用提供的测试套件运行时,出现“ IndexError:列表索引超出范围”。
ProgrammerDan

@ProgrammerDan我也一样。–
CaffeineToCode

1
@CaffeineToCode正确,但是在我提交后添加了“醉酒之路”的概念。知道什么是道路会有所帮助。根据示例,我假设两边带有分隔栏
Brian Tuck

1
@CaffeineToCode编写一个好问题的最好方法之一就是仅编写更多示例,即使没有解决方案。如果可变宽度或多车道道路有效,那么一个“疯狂”的示例将在没有任何其他描述性文字的情况下进行说明。
ProgrammerDan

1
@ProgrammerDan您要的。我的矿山现在与DR兼容(而且更短……我正在追赶)
Brian Tuck

4

Java,955个字节

显然,无论是Java还是所有人,都不会赢得任何奖项,但是我喜欢这个问题,并且想提出自己的想法。

特点和限制:

  • 可以支持不规则的道路(超级醉!),包括可变宽度,复杂线条等。
  • 期望在执行时将道路作为参数输入;非高尔夫版本也支持从stdin读取,但是由于未指定输入法,因此高尔夫版本期望最小!
  • 使用6年前左右没有使用过的动态编程技术来有效地解决O(n * m)的时间,其中n是行,m是列。
    • 从右到左求解,标记出当前索引到下一个索引的最佳方向。
    • “线”通过以下方式处理:解决它们的列,然后在下一列中解决它们。他们通过向上或向下存储方向来解决问题,最终花费的成本是非线性的。
  • 跟踪但不能打印(在高尔夫球版中)最佳解决方案的起始索引

好吧,足够的吉巴贾巴。高尔夫球版:

class C{public static void main(String[]a){int n=a.length,m=0,i=0,j=0,h=0,p=0,q=0,s=0,t=0,b=-1,c=2147483647,x=0,y=0;char[][]r=new char[n][];char u;for(String k:a){j=k.length();m=(j>m)?j:m;}for(String k:a)r[i++]=java.util.Arrays.copyOf(k.toCharArray(),m);int[][][]d=new int[n][m][2];for(j=m-1;j>=0;j--){for(i=0;i<n;i++){u=r[i][j];p=(u=='\0'||u==' '||u=='|'?0:u-'0');if(j==m-1)d[i][j][1]=p;else{if(u=='|')d[i][j][0]=-1;else{for(h=-1;h<2;h++){x=i+h;y=j+1;if(x>=0&&x<n){if(d[x][y][0]==-1){s=x-1;while(s>=0&&r[s][y]=='|')s--;t=x+1;while(t<n&&r[t][y]=='|')t++;if((s>=0&&t<n&&d[s][y][1]<d[t][y][1])||(s>=0&&t>=n)){t=d[s][y][1];s=4;}else{s=6;t=d[t][y][1];}d[x][y][0]=s;d[x][y][1]=t;}q=d[x][y][1]+p;if(d[i][j][0]==0||q<d[i][j][1]){d[i][j][0]=h+2;d[i][j][1]=q;}}}}}if(j==0&&(b<0||d[i][j][1]<c)){b=i;c=d[i][j][1];}}}String o="";i=b;j=0;while(j<m){u=r[i][j];if(u=='\0')j=m;else{o+=u+",";h=d[i][j][0]-2;if(h>1)i+=h-3;else{i+=h;j++;}}}System.out.println(o+"\b:"+c);}}

按照我的习惯,github带有ungolfed代码

“第一条”道路的解决方案:

$ java C "1356 | 1738" "3822 | 1424" "3527   3718" "9809 | 5926" "0261 | 1947" "7188   4717" "6624 | 9836" "4055 | 9164" "2636   4927" "5926 | 1964" "3144 | 8254"
0,2,0,1, , , ,1,4,1,4:13

第二个例子:

$ java C "9191 | 8282" "1919 | 2727" "5555   5555"
1,1,1,1, ,|,|, , ,2,2,2,2:12

Brian Tuck的样本:

$ java C "6417443208|153287613" "8540978161|726772300" "7294922506 263609552" "0341937695 498453099" "9417989188 370992778" "2952186385|750207767" "7049868670 756968872" "1961508589|379453595" "0670474005 070712970" "4817414691|670379248" "0297779413|980515509" "6637598208 090265179" "6872950638 767270459" "7375626432 439957105" "1387683792|544956696" "6974831376 545603884" "0949220671|632555651" "3952970630|379291361" "0456363431|275612955" "2973230054|830527885" "5328382365|989887310" "4034587060 614168216" "4487052014|969272974" "5015479667 744253705" "5756698090|621187161" "9444814561|169429694" "7697999461|477558331" "3822442188 206942845" "2787118311|141642208" "2669534759 308252645" "6121516963|554616321" "5509428225|681372307" "6619817314|310054531" "1759758306 453053985" "9356970729|868811209" "4208830142 806643228" "0898841529|102183632" "9692682718|103744380" "5839709581|790845206" "7264919369|982096148"
2,1,0,1,5,1,2,1,1,1, ,1,0,1,2,1,2,3,0,1:26

“醉酒”的Brian的例子:

6417443208 | 153287613
8540978161 | 726772300
7294922506 263609552
0341937695 498453099
9417989188 370992778
2952186385 | 750207767
7049868670 756968872
1961508589 | 379453595
0670474005 070712970
4817414691 | 670379248
0297779413 | 980515509
6637598208 090265179
6872950638 767270459
7375626432 439957105
1387683792 | 544956
697483176 5456034
09492201 | 6325551
395297030 | 3792913
 456363431 | 275612
  73230054 | 830527885
    8382365 | 989887310
    4587060 614168216
  87052014 | 96927297
 50479667 7442537
57566980 | 621187161
944481456 | 169429694
7697999461 | 477558331
3822442188 206942845
2787118311 | 141642208
2669534759 308252645
6121516963 | 554616321
5509428225 | 681372307
6619817314 | 310054531
1759758306 453053985
9356970729 | 868811209
4208830142 806643228
0898841529 | 102183632
9692682718 | 103744380
5839709581 | 790845206
7264919369 | 982096148
$ java C "6417443208|153287613" "8540978161|726772300" "7294922506 263609552" "0341937695 498453099" "9417989188 370992778" "2952186385|750207767" "7049868670 756968872" "1961508589|379453595" "0670474005 070712970" "4817414691|670379248" "0297779413|980515509" "6637598208 090265179" "6872950638 767270459" "7375626432 439957105" "1387683792|544956" "697483176 5456034" "09492201|6325551" "395297030|3792913" " 456363431|275612" "  73230054|830527885" "    8382365|989887310" "    4587060 614168216" "  87052014|96927297" " 50479667 7442537" "57566980 | 621187161" "944481456 | 169429694" "7697999461|477558331" "3822442188 206942845" "2787118311|141642208" "2669534759 308252645" "6121516963|554616321" "5509428225|681372307" "6619817314|310054531" "1759758306 453053985" "9356970729|868811209" "4208830142 806643228" "0898841529|102183632" "9692682718|103744380" "5839709581|790845206" "7264919369|982096148"
 , , , ,0,5,2,0,1, , , ,1,1,1,3,2:16

解决方案可视化:

09492201 | 6325551
395297030 | 3792913
\ 456363431 | 275612
 \ 73230054 | 830527885
  \ 8382365 | 989887310
   \ 4 \ 87060 614168216
  87/5-\ 4 | 96927 \ 97
 50479667 \ 74425/7
57566980 | \ 62- / 87161
944481456 | \ / 69429694
7697999461 | 477558331

请享用!

编辑:现在我只是炫耀(两条道路合并!他能做到吗?)

948384 | 4288324 324324 | 121323
120390 | 1232133 598732 | 123844
 293009 | 2394023 432099 | 230943
 234882 | 2340909 843893 | 849728
  238984 | 328498984328 | 230949
  509093 | 904389823787 | 439898
   438989 | 3489889344 | 438984
   989789 | 7568945968 | 989455
    568956 | 56985869 | 568956
    988596 | 98569887 | 769865
     769879 | 769078 | 678977
     679856 | 568967 | 658957
      988798 | 8776 | 987979
      987878 | 9899 | 989899
       999889 | | 989899
       989999 | | 989999
        989898 | | 998999
        989999 | | 999999
         989998 || 899999
         989998 || 998999

解:

$ java C "948384 | 4288324   324324 | 121323" "120390 | 1232133   598732 | 123844" " 293009 | 2394023 432099 | 230943" " 234882 | 2340909 843893 | 849728" "  238984 | 328498984328 | 230949" "  509093 | 904389823787 | 439898" "   438989 | 3489889344 | 438984" "   989789 | 7568945968 | 989455" "    568956 | 56985869 | 568956" "    988596 | 98569887 | 769865" "     769879 | 769078 | 678977" "     679856 | 568967 | 658957" "      988798 | 8776 | 987979" "      987878 | 9899 | 989899" "       999889 |    | 989899" "       989999 |    | 989999" "        989898 |  | 998999" "        989999 |  | 999999" "         989998 || 899999" "         989998 || 998999"
 ,2,0,3,0,0, ,|,|, ,|,|, ,|,|, ,|,|, ,|,|, ,|,|, ,|,|, , , , , , , ,|, ,|, ,|, ,|, ,|, ,|, ,|,|, , ,1,0,7,2:15

(奖金:从无高尔夫球的路径):

$ java Chicken < test5.txt
best start: 3 cost: 15
  -> 2 -> 0 -> 3 -> 0 -> 0 ->   -> | -> | ->   -> | -> | ->   -> | -> | ->   -> | -> | ->   -> | -> | ->   -> | -> | ->
  -> | -> | ->   ->   ->   ->   ->   ->   ->   -> | ->   -> | ->   -> | ->   -> | ->   -> | ->   -> | ->   -> | -> | ->
  ->   -> 1 -> 0 -> 7 -> 2 -> 15
/ -> - -> - -> \ -> / -> / -> - -> , -> , -> - -> , -> , -> - -> , -> , -> - -> , -> , -> - -> , -> , -> - -> , -> , ->
- -> , -> , -> / -> \ -> - -> - -> - -> / -> / -> ^ -> / -> ^ -> / -> ^ -> / -> ^ -> / -> ^ -> / -> ^ -> / -> , -> , ->
/ -> - -> \ -> \ -> - -> \ -> across

算法细节

要求对我采用的动态编程技术做一个更完整的解释,所以这里是:

我正在使用标记和预先计算的解决方案。它有一个专有名称,但我早已忘记它了。也许其他人可以提供它?

算法:

  • 从最右边的列开始,再向左边进行,对列中的每个单元格进行以下计算:
    • 最低成本变动的总和,定义为当前单元成本 + 下一列可到达的最低成本单元
    • 为实现此最低成本而采取的移动操作,就像从该单元格到另一个单个单元格的有效移动一样。
  • 管道被推​​迟。要解析管道,您需要计算整列,因此直到下一列我们才计算管道。
    • 在确定位于管道左侧的单元的最低成本时,我们首先计算沿管道行进的最佳方向-它始终会解析为向上或向下,因此我们只计算一次。
    • 然后,与其他所有单元格一样,我们存储最佳成本(定义为通过在管道上上下移动而达到的单元格的成本)以及到达该单元格的方向。

笔记:

而已。我们从上到下,从右到左扫描一次;管道接触(可能)的次数最多(可能是一次),但是每个管道仅“溶解”一次,使我们处于O(m * n)窗口之内。

为了处理“奇数”映射大小,我选择了简单地通过填充空字符来预扫描和规范化行的长度。空字符计为“零成本”,其移动与管道和空格相同。然后,在打印解决方案时,我停止打印成本或在到达标准化道路的边缘或到达空字符时移动。

该算法的优点是非常简单,将相同的规则应用于每个像元,通过解决O(m * n)子问题产生完整的解决方案,并且在速度方面相当快。它确实权衡了内存,有效地在道路地图的内存中创建了两个副本,第一个副本存储“最佳成本”数据,第二个副本存储每个单元格的“最佳移动”数据;这是动态编程的典型特征。


您能否再多说明一些方法?我也尝试了一种(有些不同)动态编程方法,但是却无法解决这些问题。我还考虑了一种增量(逐行)的方法来处理非常长的道路,如果不占用太多内存就不会太宽。你知道是否有办法在O(m ^ 2 * n)时间内做到这一点?
dfeuer

@dfeuer的确是权衡取舍。我认为,没有一种逐行方法能够处理输入的所有排列,而又不会在某个时刻屈服于O(m ^ n)时间。这是一个逐列构造的问题(运动在很大程度上是从左到右-有效的DP解决方案从右到左)。您可能可以执行O(m * n)的方法,以简单的后向和递归前瞻方式逐行解决问题,但是却大大增加了复杂性,却没有可能节省很多内存。
ProgrammerDan

我当时想的是,如果我没记错的话,您只需要跟踪到目前为止的最佳路径,就最近处理的行中的每个正方形而言,从左边缘到右边缘的最佳路径就是已知的,在同一行中每个正方形的右侧。错了吗
dfeuer

1
谢谢!您可以通过定义c为来缩短代码的时间-1>>>1
dfeuer

1
我的目标是Haskell,这将使它难以竞争长度,但这是我到目前为止最清楚的。
dfeuer
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.