数字三角形
这道题的题意很简单,从最上的一个点向下走,求出走到最下方获得的最大分数(路径最大和)。
很明显我们如果从上方向下走的话很难的出答案,要把每条路都走一遍然后再比较哪一条路权值之和比较大然后求出答案。这种求法无疑很麻烦,所以我们就在想如何进行优化,上一种解法中我们对于走某个点的最大值算了很多遍,但是我们使用的时候还是要再走一遍,重新搜索,造成了时间复杂度很高,所以我们可以将走某个点可以获得的最大值记录下来,进而在用的时候直接调用。为了更好的计算出这个值,我们将一个大三角形分为多个小三角形,求解小三角形的问题。 就从底部这个12 7 6 的三角形来说,如果要走6这个点,那么接下来可以获得的最大值是12,所以我们就可以将6这个点的值标记成6+12=18 即是走这个点可以获得的值,同样的,7 13 14的三角形也可以这么算,因为13>7所以走14这个点可以获得的最大值就是13,将14标记成14+13=27 ,13 24 15这个三角形同样的操作:将15标记成走这个点可以获得的最大值:15+24=39. 24 11 8的三角形同样,将8标记成32。做完这些后,我们继续向上一层推,因为现在倒数第二层的每个点都已经记录了最后一层的最优结果,所以我们可以无视最后一层了,将第4层当作最后一层继续刚刚的操作,对于18(原来6) 27(原来14) 12组成的三角形走12这个点可以得到的最大分数为12+27=39. 27 39 7同样,将7标记成7+39=46 .39 32 26 同样,将26标记成26+39=65. 现在我们又抹掉了一层,将第3层当作最后一层,继续刚刚的操作。对于39(原来12) 46(原来7) 11构成的三角形将11更新成11+36=57. 对于46(原来7) 65(原来26) 8组成的三角形,将8更新成8+65=73 . 现在只剩下两层了。原来的11被更新成了57,原来的8更新成了73.所以最后的13应该选73走,所以整个三角形最大值为13+73(原来8)=86。
Code:
#include<iostream> #include<cstdio> using namespace std; int a[101][101]; int n; int main() { int k=0; cin>>n; for(int i=1;i<=n;i++) { for(int j=1;j<=i;j++) { cin>>a[i][j]; } } a[2][1]+=a[1][1]; a[2][2]+=a[1][1]; for(int i=3;i<=n;i++) { for(int j=1;j<=i;j++) { if(a[i-1][j]>a[i-1][j-1]) a[i][j]=a[i][j]+a[i-1][j]; else a[i][j]+=a[i-1][j-1]; } } for(int i=1;i<=n;i++) { if(a[n][i]>=k) k=a[n][i]; } cout<<k; }
这道题是动态规划的入门题,虽然简单却可以很好的体现了动态规划的基本思想。刚学动态规划的同学可以看一下,理解这种分阶段解决问题的方法,省略多余的步骤以达到降低时间复杂度效果。
动态规划是将一个大问题简化为小问题以快速求出最优解的算法,要素有状态和转移方程两项,在算法竞赛及各个领域中至关重要,是数学运筹学的一个分支。
谢谢阅读。