动态规划入门--数字三角形问题
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
(图1)
图1给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。
注意:路径上的每一步只能从一个数走到下一层上和它最近的左边的那个数或者右边的那个数。
Input
输入的是一行是一个整数N (1 < N <= 100),给出三角形的行数。下面的N行给出数字三角形。数字三角形上的数的范围都在0和100之间。
Output
输出最大的和。
Sample Input
5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
Sample Output
30
方法一:递推转移方程
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn =101; 7 int s[maxn][maxn]; 8 int dp[maxn][maxn]; 9 int n; 10 11 int main(){ 12 scanf("%d",&n); 13 memset(dp,0,sizeof(dp)); 14 memset(s,0,sizeof(s)); 15 for( int i=1; i<=n; i++ ){ 16 for( int j=1; j<=i; j++ ){ 17 scanf("%d",&s[i][j]); 18 } 19 } 20 21 for( int i=1; i<=n; i++ ){ 22 dp[n][i]=s[n][i]; 23 } 24 for( int i=n-1; i>=1; i-- ){ 25 for( int j=1; j<=i; j++ ){ 26 dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+s[i][j]; 27 } 28 } 29 printf("%d\n",dp[1][1]); 30 return 0; 31 }
方法二:记忆化搜索递归
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn =101; 7 int s[maxn][maxn]; 8 int dp[maxn][maxn]; 9 int n; 10 11 /*记忆化搜索*/ 12 int solve(int i,int j){ 13 if(dp[i][j]>=0) return dp[i][j]; 14 return dp[i][j]=s[i][j]+(i==n?0:max(solve(i+1,j),solve(i+1,j+1))); 15 } 16 17 int main(){ 18 scanf("%d",&n); 19 memset(dp,-1,sizeof(dp)); 20 memset(s,0,sizeof(s)); 21 for( int i=1; i<=n; i++ ){ 22 for( int j=1; j<=i; j++ ){ 23 scanf("%d",&s[i][j]); 24 } 25 } 26 int ans=solve(1,1); 27 // for( int i=1; i<=n; i++ ){ 28 // dp[n][i]=s[n][i]; 29 // } 30 // for( int i=n-1; i>=1; i-- ){ 31 // for( int j=1; j<=i; j++ ){ 32 // dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+s[i][j]; 33 34 // } 35 // } 36 37 printf("%d\n",ans); 38 return 0; 39 }
有些目标看似很遥远,但只要付出足够多的努力,这一切总有可能实现!