动态规划(Dynamic--Planning),简称DP。
一、求解背包问题的算法归纳——以背包问题为例
1)如果装不下当前物品,那么前n个物品的最佳组合和前n-1个物品的最佳组合是一样的。
2)如果装得下当前物品。
假设1 :装当前物品,在给当前物品预留了相应空间的情况下,前n-1 个物品的最佳组合加上当前物品的价值就是总价值。
假设2:不装当前物品,那么前n个物品的最佳组合和前n-1个物品的最佳组合是-样的。
选取假设1和假设2中较大的价值,为当前最佳组合的价值。
以二维数表为例,则求解过程是从左至右,从上至下:
即先求只装入1个物品时,对应1个容量时的最大价值,再增加容量继续求此时对应的最大价值,直到容量达到MAX,再增加装入物品的数量,重复上述过程,直到物品数量为MAX时,求解完毕。
二、回溯背包物品的算法归纳——求价值最大时是装了哪些物品
我们可以看作是求最优解的逆过程,即先从数表的右下角开始回溯,如果发现前n个物品最佳组合的价值和前n-1个物品最佳组合的价值一样,说明第n个物品没有被装入。否则,第n个物品被装入。当物品编号为0时,即没有物品需要被装入,说明回溯已经结束,根据标识的结果即可得到装入了哪些物品。
输入格式
输入第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出格式
输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
演示代码:
#include<iostream>
using namespace std;
int t[101]; //存放采每种药材的时间
int v[101]; //存放每种药材的价值
int dp[101][1001]; //初始化dp状态转移数组
int max(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int T, M;
cin >> T >> M;
int i, j;
//另一种初始化数组为0的方法,调用memset()函数
//int dp[M + 1][T + 1];
//memset(dp, 0, sizeof(dp));
for(i = 1; i <= M; i++)
{
cin >> t[i] >> v[i];
}
for(i = 1; i <= M; i++)
{
for(j = 1; j <= T; j++)
{
if(t[i] > j)
{
dp[i][j] = dp[i - 1][j];
}
else
{
dp[i][j] = max( (dp[i - 1][j]), (dp[i - 1][j - t[i]] + v[i]) );
}
}
}
cout << endl << dp[M][T];
return 0;
}