动态规划其实就是,给定一个问题,我们把它拆成一个个子问题,直到子问题可以直接解决。然后呢,把子问题答案保存起来,以减少重复计算。再根据子问题答案反推,得出原问题解的一种方法。
动态规划有几个典型特征,最优子结构、状态转移方程、边界、重叠子问题。
解题思路
1.穷举分析
2.确定边界
3.找规律,确定最优子结构
4.写出状态转移方程
1.穷举分析
给定一个实例的输入:
如:T = 10 M = 5
采集药草耗费的时间 | 采集药草产生的价值 |
10 | 5 |
2 | 3 |
20 | 11 |
8 | 6 |
7 | 5 |
价值矩阵如下
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 5 |
2 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 5 |
3 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 5 |
4 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 6 | 6 | 9 |
5 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 5 | 6 | 8 | 9 |
2.确定边界
时间等于0时候,药的数量为0的时候
3.确定最优子结构
F(N) = F(i-1,N-TIME[i])+VALUE[i]
4.写出状态转移方程
如果时间足够: Dp[i][j] = Max(Dp[i-1][j-TIME[i]]+VALUE[i],Dp[i-1][j]) 如果时间不够: Dp[i][j] = Dp[i-1][j]
代码如下
#include<stdio.h>
#include<stdlib.h>
#define N 100
int dp[N][N]; //初始化数组为0
int drug[N][2]; //定义药的数组 ,第一个为数量,第二个为存放采药的时间与价值
int max(int a,int b)
{
if(a>b)
return a;
else
return b;
}
int main()
{
int time,num;
int i,j;
scanf("%d %d",&time,&num);
for(i=1;i<=num;i++)
{
for(j=0;j<2;j++)
{
scanf("%d",&drug[i][j]); //输入num个药需要采摘的时间与药的价值
}
}
for(i=1;i<=num;i++)
{
for(j=time;j>=0;j--)
{
if(j>=drug[i][0])
dp[i][j]=max(dp[i-1][j-drug[i][0]]+drug[i][1],dp[i-1][j]);
else
dp[i][j]=dp[i-1][j];
}
}
printf("%d",dp[num][time]);
return 0;
}