hihocoder(1038,1043) 01背包与完全背包

动态规划是一直感觉比较模糊的东西,虽然大致上知道是什么一回事,但是离灵活应用还差得远,但貌似比赛中动态规划的题出的特别多,这两个经典问题其实只能算是一个学习动态规划很好的模型。不过万事开头难,关键还是得静下心来多练习。

01背包的状态转移式f(i, j) = max{f(i-1, j), f(i-1, j-need[i])+value[i]}

直接按照上述的状态转移式申请二维数组进行运算,伪代码如下:

fori : 1..N  

  f(0,j) = 0

for i : 1..N

  for j : 0..M

    if(j < need(i))  f(i, j) = f(i-1, j)

    else  f(i, j) = max{f(i-1, j), f(i-1, j-need[i])+value[i]}

但是这样写,空间复杂度是非常大的,因为有一个很大的二维数组,但是仔细观察公式,或者在纸上画画格子,就会发现,每次计算所需要的只是i-1行的数据,因此,很容易想到的是可以用两行一维数组交替使用即可,但是,再仔细观察,会发现每次计算都是用的左上方的数据,这样也就是说,如果反过来计算:

for i:1..N

  for j: M..need(i)

    f(j) = max{f(j), f(j-need(i))+value(i)}

就不会覆盖“左上方”的数据,并且能顺利完成整个状态转移量的计算。

代码其实就是状态转移式了,所以说动态规划的问题,只要能列出正确的状态转移式,离AC也就不远了。

Impl:

 1 #include <iostream>
 2 using namespace std;
 3
 4 int main()
 5 {
 6     int N,M;
 7     cin >> N >> M;
 8     int *need = new int[N];
 9     int *value = new int[N];
10     for (int i = 0; i < N; ++i)
11         cin >> need[i] >> value[i];
12     int *dp = new int[M];
13
14     for (int i = 0; i < M; ++i)
15         dp[i] = 0;
16     for (int i = 0; i < N; ++i)
17         for (int j = M-1; j > need[i]; j--)
18             dp[j] = max(dp[j], dp[j-need[i]]+value[i]);
19
20     cout << dp[M-1] << endl;
21
22
23     delete [] need;
24     delete [] value;
25     delete [] dp;
26
27     return 0;
28 }

完全背包的状态转移式f(i, j) = max{f(i-1, j), f(i, j-need[i])+value[i]}

完全在描述上就是第i的物品可以取任意次,

同样的,如果直接按照上述的状态转移式申请二维数组进行运算,伪代码如下:

fori : 1..N  

  f(0,j) = 0

for i : 1..N

  for j : 0..M

    if(j < need(i))  f(i, j) = f(i-1, j)

    else  f(i, j) = max{f(i-1, j), f(i, j-need[i])+value[i]}

明显也可以优化空间复杂度,直接从数组计算上来看,每次计算f(i,j)都需要本行左端的数据,因此相对与01背包来说,这时只需要正着算就可以了。这里其实也可以理解为,01背包中循环之所以要倒着写,就是为了要响应每个物品只能用一次这个条件,而完全背包中,物品是无限制的,因此,下一个状态必须考虑其前面的子状态,所以循环便是正着的了。

for i:1..N

  for j: need(i)..M

    f(j) = max{f(j), f(j-need(i))+value(i)}

Impl:

 1 #include <iostream>
 2 using namespace std;
 3
 4 int main()
 5 {
 6     int N,M;
 7     cin >> N >> M;
 8     int *need = new int[N];
 9     int *value = new int[N];
10     for (int i = 0; i < N; ++i)
11         cin >> need[i] >> value[i];
12     int *dp = new int[M];
13
14     for (int i = 0; i < M; ++i)
15         dp[i] = 0;
16     for (int i = 0; i < N; ++i)
17         for (int j = need[i]; j < M; ++j)
18             dp[j] = max(dp[j], dp[j-need[i]]+value[i]);
19
20     cout << dp[M-1] << endl;
21
22
23     delete [] need;
24     delete [] value;
25     delete [] dp;
26
27     return 0;
28 }

时间: 2024-08-23 11:40:27

hihocoder(1038,1043) 01背包与完全背包的相关文章

有关货币问题的动态规划题目--有关01背包,完全背包,多重背包

背包dp:参考背包九讲以及给出一些题目 01背包 (先枚举物品,再逆序枚举容量) 给定n件物品和一个容量为V的背包,每件物品的体积是w[i],价值是va[i](1<=i<=n),求在不超过背包的容量的情况下,怎么选择装这些物品使得得到的价值最大? 例如:有5件物品,体积分别是{2,2,6,5,4},价值分别是{6,3,5,4,6} 递归式:F(i,v)=max(F(i-1,v), F(i-1,v-w[i])+va[i]),其中F(i,v)表示把前i种物品恰放入背包容量为v时取得的最大价值 把这

HDU 3033 I love sneakers! (01背包+反分组背包)

题意:给你 n,m,k,表示有k种鞋子共n双,你有m的容量: 每双鞋子有容量p和价值v:问是否买全k种鞋子,若能在容量为m的情况下最多能买到鞋子的价值为多少: 每双鞋子只能买一次(01背包),每种鞋子至少买一种(分组背包:每组只能有一个)与传统分组背包的限制相反. 注意初始化!!! #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map&g

【背包问题】0-1背包、完全背包、多重背包、混合三种背包、二位费用背包、分组背包

一.0-1背包问题 输入:第一行物品的个数n,第二行背包的质量m,随后n行每行给出每个物品的重量和价值,每种物品只有一个. 输出:背包可以达到的最大价值 样例输入: 5 10 1 5 2 4 3 3 4 2 5 1 样例输出: 14 动态规划的过程中需要逆序,因为如果不是逆序那么 当i=0的时候 f[0]=0; f[1]=max(f[1],f[1-w[0]]+v[0])=5; f[2]=max(f[2],f[2-w[0]]+v[0])=10; f[3]=max(f[3],f[3-w[0]]+v[

【算法学习笔记】30.动态规划 01背包和完全背包的关系

首先先说明一下01背包和完全背包问题的区别 01背包:有 N 件物品和一个容量为 V 的背包.放入第 i 件物品耗费的费用是 Ci,得到的价值是 Wi.求解将哪些物品装入背包可使价值总和最大.(可以不装满) 完全背包:有 N 种物品和一个容量为 V 的背包,每种物品都有无限件可用.放入第 i 种物品 的费用是 Ci,价值是 Wi.求解:将哪些物品装入背包,可使这些物品的耗费的费用总和不超过背包容量,且价值总和最大. 先说结论: 两个问题的最优解都要用DP来解决,实现的过程也非常像只是在内层循环中

背包之01背包、完全背包、多重背包详解

首先说下动态规划,动态规划这东西就和递归一样,只能找局部关系,若想全部列出来,是很难的,比如汉诺塔.你可以说先把除最后一层的其他所有层都移动到2,再把最后一层移动到3,最后再把其余的从2移动到3,这是一个直观的关系,但是想列举出来是很难的,也许当层数n=3时还可以模拟下,再大一些就不可能了,所以,诸如递归,动态规划之类的,不能细想,只能找局部关系. 1.汉诺塔图片 (引至杭电课件:DP最关键的就是状态,在DP时用到的数组时,也就是存储的每个状态的最优值,也就是记忆化搜索) 要了解背包,首先得清楚

01背包、完全背包

01背包 问题描述 有n个重量(费用)和价值分别为wi,vi的物品.从这些物品中挑选出总重量(费用)不超过W的物品,求所有挑选方案中价值总和的最大值. 例子 n=4 (w,v)={(2,3),(1,2),(3,4),(2,2)} W=5 输出:7 1 二维数组版:时间复杂度O(nW) ,空间复杂度O(nW) 记得以下所有方法首先都要初始化dp数组memset(dp,0,sizeof(dp)); dp[i][j] :表示从前i个物品中选出总重量不超过j的物品时总价值的最大值. int dp[MAX

背包整理(01背包,完全背包,多重背包,分组背包)(待更新)

目录 01背包 优化(空间) 完全背包 优化 多重背包 优化 分组背包 01背包 有N件物品和一个容量为V的背包.第i件物品的价格(即体积,下同)是w[i],价值是c[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大. 对于每个物品,我们有两种选择:把这个物品放进背包还是不放. d[i][v]表示前i件物品,恰放入容积为v的背包时的价值总和. 状态转移方程为 \[d[i][v] = \max(d[i - 1][v],d[i - 1][v - w[i]] + c[i

01背包与完全背包(dp复习)

01背包和完全背包都是dp入门的经典,我的dp学的十分的水,借此更新博客的机会回顾一下 01背包:给定总容量为maxv的背包,有n件物品,第i件物品的的体积为w[i],价值为v[i],问如何选取才能是背包内的物品价值总和最大. stdin: 5 1 2 3 4 5 5 4 3 2 1 stdout: 14 设dp[i][j]为取前i件物品时容量为j的最优解. 状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]); 压缩后:dp[j]=max(d

白话背包之完全背包

借着前面的  白话背包之01背包 的基础,来结合图看看完全背包是个什么东东,希望以后自己看能一目了然,能对刚接触的童鞋有帮助是最好不过滴 一:关于完全背包 有N个物品,每个物品(有无限多个) i 对应有重量w[i].价值va[i].有一个背包可以放M重的物品,现在让你从N钟物品中选择一些物品,在不超过背包上限情况使得背包装的价值最大. 二:初步了解完全背包算法 那么这里看看状态转移方程: dp[i][j]=max{dp[i-1][j-k*w[i]]+k*va[i] | 0<=k*va[i]<=