动态规划问题一直以来都是利用空间换取时间。
动态规划问题一直以来最经典的就是 0 1背包问题 ,再有点难度就是 完全背包问题 以及多重背包问题
0-1背包问题
题目描述:有一个容量为 V 的背包,和一些物品。这些物品分别有两个属性,体积 w 和价值 v,每种物品只有一个。要求用这个背包装下价值尽可能多的物品,求该最大价值,背包可以不被装满。
其实这问题刚接触是 我靠 一脸懵逼 这是考数学呀!!! 瞬间感觉干饭都不香了。
其实只需要考虑每个物品两种形式 在 背 包 和 没 在 背 包 在背包 和 没在背包 在背包和没在背包
第一步 对于每一个物品,有两种结果:能装下或者不能装下。
第一,包的容量比物品体积小,装不下,这时的最大价值和前i-1个物品的最大价值是一样的。(就是说口袋太小了 放不进去 ,,但是物品价值 和口袋里的物品一样值钱)
第二,还有足够的容量装下该物品,但是装了不一定大于当前相同体积的最优价值,所以要进行比较。(就是说 口袋很大 还能放里面 ,,但是和已经有的物品比较 说不来值钱还是不值钱)
第二步 就是考虑边界条件(万一装把口袋撑破了 ,是不是啥都装不进去了)
dp[i][j]啥意思 这样定义 就是说 把i个物品 装进 背包容量为 j 的背包 达到最大RMB价值。
初始时: dp[0][j]=0 (0<=j<=V)
来翻译一下 就是说 开始 i为0 里面没有东西 是空口袋 但是 j 不变 因为 口袋本身容量就这样大,里面没有东西 自然就不值钱为0
第三步考虑变换过程 就是转移状态
第i个物品的体积为w,价值为v,则状态转移方程为
当 j<w 时 dp[i][j]= dp[i-1][j]; 翻译一下 就是说第i件东西装不下 ,而且最大价值不改变,也就是有i行 没i也行 价值没变,但是有i容量就过载了
当 j<=w dp[i][j]=max(dp [i-1][ j-l ist[i].w] + v, dp[i-1][j]);这段太长了
解释一下 就是说 dp[i][j] 的值 由装i前的一个决定 比如 已经装了3斤 现在要装5斤 那么装这5斤 得看3斤装后的状态 万一3斤装了没位置了 那就不用装5斤了 。
所与i的前一个 dp[i-1][j-list[i].w] 这里加入v就好比 能装下5 斤,后边理解为 比较原本最大价值 如果装了价值变小了 还不如不装,所以求最大值 看看那各价值最大
接下来下代码 也是最头疼的
最大值就这
int max(int a, int b)//取最大值函数
{
return a > b ? a : b;
}
背包结构体 和dp
struct Thing
{
int w;
int v;
}list[101];
int dp[101][1001];
终极main函数
int main()
{
int s, n;//背包容量和物品总数
while (scanf("%d%d", &s, &n) != EOF)
{
for (int i = 1; i <= n; i++)
{
scanf("%d%d", &list[i].w, &list[i].v);//读入每个物品的体积和价值
}
dp[0][0] = 0;
for (int i = 1; i <= s; i++) dp[0][i] = INF;//初始化二维数组
for (int i = 1; i <= n; i++)//循环每个物品,执行状态转移方程
{
for (int j = s; j >= list[i].w; j--)
{
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - list[i].w] + list[i].v);
}
for (int j = list[i].w - 1; j >= 0; j--)
{
dp[i][j] = dp[i - 1][j];
}
}
printf("%d\n", dp[n][s]);
}
return 0;
}
这里注意个问题 我是倒写
for (int j = s; j >= list[i].w; j--)
for (int j = list[i].w - 1; j >= 0; j--)
why why why 举手回答
那是因为 要求恰好装满背包时,把dp[0][0]设为0,其余dp[0][i]设为负无穷即可,这样只有恰好达到dp[n][s]时,dp[n][s]才为正值,所以 我们直接就认为 背包能装满s 容量 进而判断 当容量大于 i 间物品是就装入进去 , 来来 给画画
下节说说 用滚动数组优化问题 二维变一维