其实数字三角形网上的代码无数,别人也讲得很好,而且这个题的难度不大,但是这道题作为入门动态规划和学习使用备忘录以及递归到递推的转换真的很适合,而且我感觉毕竟自己写的东西除了记忆更深刻以外,下次回顾的时候也就更加亲切,过往的记忆很快被打通,所以我决定还是把自己写的代码再上传上去,起到总结和复习的作用。
1按照思路可以写出使用递归的代码如下
1 #include<bits/stdc++.h> 2 using namespace std; 3 int array[100][100]; 4 int n; 5 int path[100]={0}; 6 int f(int r,int j){ 7 if(r==n-1){ 8 return array[r][j]; 9 } 10 int num1=f(r+1,j); 11 int num2=f(r+1,j+1); 12 if(num1>num2){ 13 return num1+array[r][j]; 14 } 15 else{ 16 return num2+array[r][j]; 17 } 18 } 19 int main() 20 { 21 22 cin >> n; 23 memset(array,0,sizeof(array)); 24 for(int i=0;i<n;i++){ 25 for(int j=0;j<=i;j++){ 26 cin >> array[i][j]; 27 } 28 } 29 cout << f(0,0); 30 return 0; 31 }
此时代码的复杂度为2^n显然需要改进
分析如下
2根据思路可知利用备忘录算法可以大大降低复杂度,代码如下
1 #include<bits/stdc++.h> 2 using namespace std; 3 int array[100][100]; 4 int n; 5 int path[100][100];//用来表示该位置有没有计算过,没有就计算,有就直接使用 6 int f(int r,int j){ 7 if(r==n-1){ 8 return array[r][j]; 9 } 10 if(path[r+1][j]==-1){//没有就计算 11 path[r+1][j]=f(r+1,j); 12 } 13 if(path[r+1][j+1]==-1){ 14 path[r+1][j+1]=f(r+1,j+1); 15 } 16 if(path[r+1][j]>path[r+1][j+1]){//直接使用计算过的 17 return path[r+1][j]+array[r][j]; 18 } 19 else{ 20 return path[r+1][j+1]+array[r][j]; 21 } 22 } 23 int main() 24 { 25 cin >> n; 26 memset(array,0,sizeof(array)); 27 for(int i=0;i<100;i++){ 28 for(int j=0;j<100;j++){ 29 path[i][j]=-1; 30 } 31 } 32 for(int i=0;i<n;i++){ 33 for(int j=0;j<=i;j++){ 34 cin >> array[i][j]; 35 } 36 } 37 cout << f(0,0); 38 return 0; 39 }
3递推法
从底向上递推,出最后一行外,每一行的每个点的最大值等于自身加上下面一行对应左右两个点的最大值,从下往上递推,最顶部的即所求。比如下图所示。首先最后一行的最大值就是它本身。倒数第二行第一个数7就是输入的倒二行的第一个数2 + 4 和 2 +5 取最大值 。逐步递推到顶部。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int array[100][100]; 4 int main() 5 { 6 int n; 7 cin >> n; 8 memset(array,0,sizeof(array)); 9 for(int i=0;i<n;i++){ 10 for(int j=0;j<=i;j++){ 11 cin >>array[i][j]; 12 } 13 } 14 for(int i=n-2;i>=0;i--){ 15 for(int j=0;j<=n-2;j++){//对左右两边的数字进行选择,较大的加上去 16 if(array[i+1][j]>array[i+1][j+1]) 17 array[i][j]+=array[i+1][j]; 18 else{ 19 array[i][j]+=array[i+1][j+1]; 20 } 21 } 22 } 23 cout << array[0][0] << endl; 24 return 0; 25 }
4使用递推法并打印路径
因为上一行都是加上下一行的较大者才保证上一行值最大,所以我们可以通过从第一行向下比较较大者便是经过的路径
即
等价于
代码如下
1 #include<bits/stdc++.h> 2 using namespace std; 3 int array[100][100]; 4 int array1[100][100]; 5 int main() 6 { 7 int n; 8 cin >> n; 9 memset(array,0,sizeof(array)); 10 memset(array1,0,sizeof(array1)); 11 for(int i=0;i<n;i++){ 12 for(int j=0;j<=i;j++){ 13 cin >>array[i][j]; 14 array1[i][j]=array[i][j]; 15 } 16 } 17 for(int i=n-2;i>=0;i--){ 18 for(int j=0;j<=n-2;j++){//对左右两边的数字进行选择,较大的加上去 19 if(array[i+1][j]>array[i+1][j+1]) 20 array[i][j]+=array[i+1][j]; 21 else{ 22 array[i][j]+=array[i+1][j+1]; 23 } 24 } 25 } 26 cout << array[0][0] << endl; 27 cout << "路径为:"<< endl; 28 cout << array1[0][0]<< "--->"; 29 int u1=0; 30 int u2=0; 31 32 for(int i=u1;i<n-1;i++){ 33 for(int j=u2;j<=i;j++){ 34 if(array[i+1][j]>array[i+1][j+1]){ 35 cout << array1[i+1][j] << "--->"; 36 u2=j; 37 break; 38 } 39 else{ 40 cout << array1[i+1][j+1] << "--->"; 41 u2=j+1; 42 break; 43 } 44 } 45 } 46 cout << "结束"; 47 return 0; 48 }
运行结果截图
递推时间复杂度要优于递归