经典的数字三角问题
刚学了动态规划,数字三角问题就是动态规划的金典案例,下面来分享一下我对此案例的理解
一、问题描述
数字三角形。如下图所示的数字三角形,从三角形的顶部到底部有很多条不同的路径。
对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。
编写一个程序求出最佳路径上的数字之和。
【注意:路径上的每一步只能从一个数走到下一层上和它最近的左边的数或者右边的数。】
7
3 8
8 1 2
2 7 4 4
4 5 2 6 5
对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。
编写一个程序求出最佳路径上的数字之和。
【注意:路径上的每一步只能从一个数走到下一层上和它最近的左边的数或者右边的数。】
7
3 8
8 1 2
2 7 4 4
4 5 2 6 5
二、解题思路
1、经典递归解法
int minPath(int x, int y){
if(x == M)
return A[x][y];
int i = minPath(x + 1, y);
int j = minPath(x + 1, y - 1);
return min(i,j) + A[x][y];
}
上面递归解法可是可以,但有大量的重复计算,时间复杂度为2^n。
2、采用备忘录
用数组D[x][y]记录已经计算过的值,当此计算再次出现时就不用重复计算,直接把数组中的值拿出来使用即可,从而避免了大量重复计算,时间复杂度为n^2。
int minPath(intx, inty){
if(D[x][y]!=-1) return D[x][y];
if(x == M) {
D[x][y] = A[x][y];
}
else {
int i = minPath(x + 1, y);
int j = minPath(x + 1, y - 1);
D[x][y] = min(i,j) + A[x][y];
}
return D[x][y];
}
此数字三角问题的解题思路:
用二元组D(X,Y)描述问题,D(X,Y)表示到达第X层第Y个位置时的得分,那么D(X,Y)的最优解包含了子问题D(X+1,Y)或D(X+1,Y+1)的最优解,状态转移方程为 :
D(X, Y)= min{D(X+1,Y), D(X+1,Y+1)} + A[X,Y]
int minPath(int A[101][101],int D[101][101],int n)
{
int i,j;
for(j=1; j<=n; j++)
D[n][j]=A[n][j];//从最后一行开始;
for(i=n-1; i>=1; i--)//自底向上DP
for(j=1; j<=i; j++)
{
if(D[i+1][j+1]>D[i+1][j]) D[i][j]=A[i][j]+D[i+1][j+1];
else
D[i][j]=A[i][j]+D[i+1][j];
}
return D[1][1];//输出第一行
}
{
int i,j;
for(j=1; j<=n; j++)
D[n][j]=A[n][j];//从最后一行开始;
for(i=n-1; i>=1; i--)//自底向上DP
for(j=1; j<=i; j++)
{
if(D[i+1][j+1]>D[i+1][j]) D[i][j]=A[i][j]+D[i+1][j+1];
else
D[i][j]=A[i][j]+D[i+1][j];
}
return D[1][1];//输出第一行
}
三、附上我自己写的源代码
#include <stdio.h>
#include <stdlib.h>
int minPath(int A[101][101],int D[101][101],int n)
{
int i,j;
for(j=1; j<=n; j++)
D[n][j]=A[n][j];//从最后一行开始;
for(i=n-1; i>=1; i--)//自底向上DP
for(j=1; j<=i; j++)
{
if(D[i+1][j+1]>D[i+1][j]) D[i][j]=A[i][j]+D[i+1][j+1];
else
D[i][j]=A[i][j]+D[i+1][j];
}
return D[1][1];//输出第一行
}
int main()
{
int n,A[101][101],D[101][101],i,j,x;
printf("请输入数字三角的行数:\n");
scanf("%d",&n);//输入行数
printf("请输入数字三角的信息:\n");
for(i=1; i<=n; i++)
for(j=1; j<=i; j++)
scanf("%d",&A[i][j]);
x=minPath(A,D,n);
printf("最佳路径上的数字之和为:%d\n",x);
return 0;
}
#include <stdlib.h>
int minPath(int A[101][101],int D[101][101],int n)
{
int i,j;
for(j=1; j<=n; j++)
D[n][j]=A[n][j];//从最后一行开始;
for(i=n-1; i>=1; i--)//自底向上DP
for(j=1; j<=i; j++)
{
if(D[i+1][j+1]>D[i+1][j]) D[i][j]=A[i][j]+D[i+1][j+1];
else
D[i][j]=A[i][j]+D[i+1][j];
}
return D[1][1];//输出第一行
}
int main()
{
int n,A[101][101],D[101][101],i,j,x;
printf("请输入数字三角的行数:\n");
scanf("%d",&n);//输入行数
printf("请输入数字三角的信息:\n");
for(i=1; i<=n; i++)
for(j=1; j<=i; j++)
scanf("%d",&A[i][j]);
x=minPath(A,D,n);
printf("最佳路径上的数字之和为:%d\n",x);
return 0;
}
四、运行结果
望对各位有所帮助,不足之处还请各位大佬指出!