您的位置:首页 > 其它

【动态规划】动态规划解题的一般思路——以数字三角形为例

2017-09-20 22:37 239 查看
/*(POJ1163)数字三角形

*在数字三角形 中寻找一条从顶部到底边的路径,

* 使得路径上所经过的数字之和最大,路径上的每一步都只能往左下或者右下走。

*只需要求处这个最大和即可,不必给出具体路径

输入格式:

5 // 三角形行数。下面是三角形

7

3 8

8 1 0

2 7 4 4

4 5 2 6 5

要求输出最大和

*/

解题思路:

- 我们用一个二维数组D[r][j]储存第r行第j个数字,

- 函数MaxSum(i,j) 求从D(r,j)到底边的各条路径中,最佳路径的数字之和。

则可将此问题转化为典型的递归问题:

从D( i , j )出发,下一步只能走D( i+1, j ) 或者 D( i+1, j+1 )。

此时我们要求出从底边到 第i行 j列 的最佳路径MaxSum( i ,j ),

1. 先求出MaxSum(i+1, j)和MaxSum( i+1, j+1 ),

2. MaxSum( i , j )的值为其下第 i+1行的两个可进入的MaxSum的值中的较大者 + D[i][j]

3. 考虑边界,其最底行的MaxSum即为其本身

代码实现如下:

#include <iostream>
#include <algorithm>
#define MAX 101
using namespace std;

int N; //储存三角形的行数

int D[MAX][MAX];
int maxSum[MAX][MAX];
int MaxSum(int i,int j)  //第r行第j个数字(r,j从1开始)
{
if(maxSum[i][j] != -1)
return maxSum[i][j];
if(i == N)
maxSum[i][j] = D[i][j];
else
{
int x = MaxSum(i+1,j);
int y = MaxSum(i+1,j+1);
maxSum[i][j] = max(x,y) + D[i][j];
}
return maxSum[i][j];
}

int main()
{
cin >> N;
for(int i = 1;i <= N; ++i)
for(int j = 1;j <= i;++j)
{
cin >> D[i][j];
maxSum[i][j] = -1;
}
cout << MaxSum(1,1) << endl;
return 0;
}


以这种方式,我们实现了动态规划最关键的第一步:

1.将原问题分解为子问题

子问题与原问题形式相同或相似,不过规模变小,只要子问题解决,原问题便解决。

例:在数字三角形中,要求MaxSum( i , j ) 则必须先求规模更小的 MaxSum( i+1, j ) 和MaxSum( i+1, j+1)并比较其大小。

子问题的解一旦求出就会被保存,所以每个子问题只需求解一次。

2.确定状态

在用动态规划解题时,我们往往和子问题相关的各个变量的一组取值,称为一个“状态”。一个“状态”对应与一个或多个子问题。某个“状态”下的“值”,就是这个状态所对应的子问题的解。

例:在数字三角形中 MaxSum(i,j)的一组取值(i , j)即为一个状态

同时,每个状态的值仅需计算一次,我们要用一个数组将所有计算的值储存起来

3. 确定初始状态(边界条件)

以数字三角形为例,初始状态就是底边数字,值就是底边数字。

4.确定状态转移转移方程

即如何一个或多个“值”已知的状态,求出另一个“状态”的值。

数字三角形的状态转移方程:

MaxSum[r][j] = { D [i] [j] ( 当 r = N ,边界情况) } 或 { Max ( MaxSum[ r + 1 ] [ j ] , MaxSum[ r + 1 ] [ j + 1] ) + D [ r ] [ j ] (其他情况) }

由递归到递推

#include <iostream>
#define MAX 101
int N;
int D[MAX][MAX];
int Max[MAX][MAX];
void CountMax()
{
for(int i = 1;i <= N;++i )
Max
[i] = D
[i];
for(int i = N-1;i >= 1; --i)
for(int j = 1; j <= i ; ++j)
{
int a = Max[i+1][j];
int b = Max[i+1][j+1];
int m = a > b ? a : b;
Max[i][j] = m + D[i][j];
}
}

using namespace std;
int main()
{
cin >> N;
for(int i = 1; i <= N; ++i)
for(int j = 1; j <= i;++j)
cin >> D[i][j];
CountMax();
cout << Max[1][1] << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: