动态规划(Dynamic Programming, DP)
1. 基本思想
定义
所谓动态规划是指,问题有多个可行解,每个可行解对应一个目标值,目的就是要在可行解中求出最优值(最大或者最小)
- 目标:通常用于求解某种具有最优性质的问题
- 基本思路:将待求解的问题先分解成若干个子问题,先求解子问题,然后从这些子问题中得到原问题的解
和分治的不同
- 适用于动态规划求解的问题,经过分解得到的子问题往往是不相互独立的。
- 我们用一个表来记录所有已经求解的子问题的答案。不管子问题的解是否在后来被用到,只要是计算过的,就存储在表中。
具体的动态规划问题多种多样,但是它们都具有相同的填表结构
2. 设计动态规划的方法步骤
1. **找出最优解的性质,并刻画其结构特征;**
2. **递归地定义最优值(写出动态规划方程);**
3. **自底而上地方式计算出最优值;**
4. **根据最优值得到的性质,构造一个最优解;**
3. 动态规划的特征
- 最优子结构性质:当问题的最优解包含其子问题的最优解时,称该问题具有最优子结构性质
- 重叠子问题 :对于每个子问题只解一次,然后将其解保存在一个表格中,以后尽可能用这些子问题的解
矩阵链乘法
void matixChain(int n,int **p,int **m,int **s)
{
for(int i=1;i<=n;i++)//表m中存储dp子问题的解
m[i][i]=0;//当矩阵链中只有一个矩阵时的平凡情况,故为0
for(int r=2;r<=n;r++)
for(int i=1;i<=n-r+1;i++)//形成上三角结构表
{
int j=i+r-1;//计算初值,从i处断开
m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];//向量P中存储的是各个行数
s[i][j]=i;//保存加括号的位置
for(int k=i+1;k<j;k++)//处理的范围是从编号为i的矩阵到编号为j的矩阵链的练成问题
{
int t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if(t<m[i][j])
{
m[i][j]=t;//储存子问题的最优解
s[i][j]=k;//保存子问题取得最优解时矩阵链在哪里加的括号
}
}
}
}
void trackBack(int i,int j,int **s) //构造最优解
{
if(i==j)return ;
trackBack(i,s[i][j],s);
trackBack(s[i][j]+1,j,s);
printf("Multiply A %d,%d",i,s[i][j]);
printf("and A%d, %d",s[i][j]+1,j);
}
例2,ACM经典问题——树塔
概述:给出一个数字三角形,编写一个程序,计算出从顶至底的某处的一条路径,使得该路径所经过的数字的总和最大。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN=111;
int dp[MAXN][MAXN]={0};
int main()
{
int T,n;
scanf("%d",&T) ;
while (T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
for (int j=1;j<=i;j++){
scanf("%d",&dp[i][j]);//构造一个树塔
printf("Old dp[%d][%d]=%d\n",i,j,dp[i][j]);
}
}
for(int i=n-1;i>=1;i--){
for (int j=1;j<=i;j++){
dp[i][j]+=max(dp[i+1][j],dp[i+1][j+1]);//状态转移方程
printf("New dp[%d][%d]=%d\n",i,j,dp[i][j]);
}
}
printf("%d\n",dp[1][1]);
}
return 0;
}
*结题报告*
如果自上而下考虑,需要深度搜索,查找每一条路径,并记录数值,比较大小。
采取自下而上考虑,从最基本的两层树塔n==2为模型,两个点比较大小即可;再看n==3,除掉塔顶,就可以看作是两个n==2时的情况。如果确定走某一棵树(n==3),必然会走这棵树上的最大的路径,所以只要得到两棵n==2的树的最大路径,分别进行比较,就能得到n==3树上的最大路径;
同理,n==4,…
核心:状态转移方程,dp[i][j]+=max( dp[i+1][j], dp[i+1][j+1] )
我将这个树塔倒置,
4 5 2 6 5 button
2 7 4 4
8 1 0
3 8
7 top
按照算法执行:
i=4
4 5 2 6 5 button
'7' '12' '10' '10' i=4
8 1 0 i=3
3 8 i=2
7 top
i=3
4 5 2 6 5 button
7 12 10 10 i=4
'20' '13' '10' i=3
3 8 i=2
7 top
i=2
4 5 2 6 5 button
7 12 10 10 i=4
20 13 10 i=3
'23' '21' i=2
7 top
i=1
4 5 2 6 5 button
7 12 10 10 i=4
20 13 10 i=3
23 21 i=2
'30' top
将max改为min就可以求最小路径