问题描述
小Hi和小Ho在经历了螃蟹先生的任务之后被奖励了一次出国旅游的机会,于是他们来到了大洋彼岸的美国。美国人民的生活非常有意思,经常会有形形色色、奇奇怪怪的活动举办,这不,小Hi和小Ho刚刚下飞机,就赶上了当地的迷宫节活动。迷宫节里展览出来的迷宫都特别的有意思,但是小Ho却相中了一个其实并不怎么像迷宫的迷宫——因为这个迷宫的奖励非常丰富~
于是小Ho找到了小Hi,让小Hi帮助他获取尽可能多的奖品,小Hi把手一伸道:“迷宫的介绍拿来!”
小Ho选择的迷宫是一个被称为“数字三角形”的n(n不超过200)层迷宫,这个迷宫的第i层有i个房间,分别编号为1..i。除去最后一层的房间,每一个房间都会有一些通往下一层的房间的楼梯,用符号来表示的话,就是从第i层的编号为j的房间出发会有两条路,一条通向第i+1层的编号为j的房间,另一条会通向第i+1层的编号为j+1的房间,而最后一层的所有房间都只有一条离开迷宫的道路。这样的道路都是单向的,也就是说当沿着这些道路前往下一层的房间或者离开迷宫之后,小Ho没有办法再次回到这个房间。迷宫里同时只会有一个参与者,而在每个参与者进入这个迷宫的时候,每个房间里都会生成一定数量的奖券,这些奖券可以在通过迷宫之后兑换各种奖品。小Ho的起点在第1层的编号为1的房间,现在小Ho悄悄向其他参与者弄清楚了每个房间里的奖券数量,希望小Hi帮他计算出他最多能获得多少奖券。
提示一:盲目贪心不可取,搜索计算太耗时
小Hi拿到迷宫的介绍,仔细想了想,问道:“你自己有什么思路么?”
小Ho想了想,道:“反正每次只有两种选择,我就选通向有更多奖券的房间的那条路呗~”
小Hi笑了笑:“你这叫盲目贪心,如果我是迷宫的创造者,一定在第2层的第1个房间放10张奖券,第2个房间一张不放,然后在第3层的第3个房间放999张奖券,这样你就因为占一点小便宜就失掉了大头,你说是不是?”
小Ho一惊:“似乎是的!切记不可因小失大,那……既然我们都是学计算机的学生,不如我们用计算机枚举一下所有可能的路径,然后找到最优的那一条?”
小Hi点了点头:“自然是要用计算机来解决这个问题,不过你得先计算一下总共有多少条可能的路径,估算一下运行时间,这样才能确定能不能在迷宫节结束之前计算完是不是~”
“我来算算,从出发点开始,每次我都有两种选择,而我总共要做n-1次选择,也就是2的n-1次方,而n最大可能是200,也就是说有2^199条路径……哪怕每条路径我只用一次运算就可以算出它的奖券总数,我毕业之前都肯定算不出来了吧QAQ”小Ho得出了一个非常忧伤的结论。
“是的,但是这种搜索的方法其实是可以有方法进行优化的哦~”小Hi循循诱导着。
“什么样的方法?”
提示二:记忆深搜逞神威,宽度优先解难题
输入
每个测试点(输入文件)有且仅有一组测试数据。
每组测试数据的第一行为一个正整数n,表示这个迷宫的层数。
接下来的n行描述这个迷宫中每个房间的奖券数,其中第i行的第j个数代表着迷宫第i层的编号为j的房间中的奖券数量。
测试数据保证,有100%的数据满足n不超过100
对于100%的数据,迷宫的层数n不超过100
对于100%的数据,每个房间中的奖券数不超过1000
对于50%的数据,迷宫的层数不超过15(小Ho表示2^15才3万多呢,也就是说……)
对于10%的数据,迷宫的层数不超过1(小Hi很好奇你的边界情况处理的如何?~)
对于10%的数据,迷宫的构造满足:对于90%以上的结点,左边道路通向的房间中的奖券数比右边道路通向的房间中的奖券数要多。
对于10%的数据,迷宫的构造满足:对于90%以上的结点,左边道路通向的房间中的奖券数比右边道路通向的房间中的奖券数要少。
输出
对于每组测试数据,输出一个整数Ans,表示小Ho可以获得的最多奖券数。
5 2 6 4 1 2 8 4 0 9 6 6 5 5 3 6Sample Output
28
1 /* 2 问题 第i行有i个数字的数字三角形,从第一行走到末行,每个数字只能向直下和下右走,计算并输出最多奖券数 3 变量 行数,房间数,奖券数 4 抽象问题 从起点位置走到第i行第j个房间,最多的奖券数价值是多少 5 无后效性 之前作出的选择对后面的选择没有限制和优待 6 重复子问题 将从起点出发到走出迷宫的最优路分解成了两个子问题, 7 其一是从第2层的第1个房间走出迷宫的最优路, 8 其二是从第2层的第2个房间走出迷宫的最优路,只要能算出这两个部分的最优值,我们就可以知道从起点出发到走出迷宫的最优路。 9 照这样的方法,这两个子问题都有一个相同的子问题——从第3层的第2个房间出发走出迷宫的最优路。 10 11 状态 best[i][j]表示从起点出发到达第i行第j个房间,能够获得的最多奖券数 12 状态转移 best[i][j]=max(best[i-1][j],best[i-1][j-1]) + map[i][j]; 13 边界确定 j=1时,best[i][j]=best[i-1][j] + map[i][j]; 14 j=i时,best[i][j]=best[i-1][j-1] + map[i][j]; 15 */ 16 #include<stdio.h> 17 /*const int N=110;GCC编译器中const定义的N会报错,因为在C语言中,const不是一个真真正正的常量,其代表的含义仅仅是只读。 18 使用const声明的对象是一个运行时对象,无法使用其作为某个量的初值、数组的长度、case的值或在类型的情形中使用。需要替换成 19 下面的define定义*/ 20 #define N 100 21 int map[N][N]; 22 int best[N][N]; 23 int max(int x,int y){ 24 return x>y?x:y; 25 } 26 int main() 27 { 28 int n,i,j; 29 while(scanf("%d",&n) != EOF) 30 { 31 for(i=1;i<=n;i++) 32 for(j=1;j<=i;j++) 33 scanf("%d",&map[i][j]); 34 best[1][1]=map[1][1]; 35 for(i=2;i<=n;i++){ 36 for(j=1;j<=i;j++){ 37 if(j==1) 38 best[i][j]=best[i-1][j]+map[i][j]; 39 else if(j==i) 40 best[i][j]=best[i-1][j-1]+map[i][j]; 41 else 42 best[i][j]=max(best[i-1][j],best[i-1][j-1]) + map[i][j]; 43 } 44 } 45 int ans=-1; 46 for(i=1;i<=n;i++){ 47 if(best[n][i] > ans) 48 ans=best[n][i]; 49 } 50 printf("%d\n",ans); 51 } 52 return 0; 53 }