当前位置:网站首页>背包问题-动态规划-理论篇
背包问题-动态规划-理论篇
2022-08-02 14:10:00 【老顽固也可爱】
01背包
现在有n个物品,每个物品最多取一次, 有一个背包,它所装物品重量之和不能超过W,第i个物品它的重量是wi,价值是vi, 现在的问题是,在不超过背包容量的限制下,最多能获得的物品价值之和是多少。
(1<=n<= 2000, 0<= W<= 2000, vi>0, wi> 0)
解决方案1
我们先考虑遍历所有的方法,如果物品个数为n,那么总的方案数就是2 ^ n种(选或者不选),我们可以用dfs搜索实现。
//递归的解决的代码,需要用记忆化搜索
int dfs(int i, int j)
{
if(i==0||j<0) return 0;
if(dp[i][j]!=-1) return dp[i][j];
dp[i][j]= dfs(i-1,j);
if(j>=w[j])dp[i][j]=max(dp[i][j],dfs(i-1,j-w[i]));
return dp[i][i];
}
/*初始化dp数组为-1, answer=dfs(n, W). 尝试把递归解决动态规划和搜索进行对比。*/
但是n最大能到达2000,显然2 ^ 2000的复杂度难以接受,我们能不能得到一种时间复杂度更小的方法呢?
解决方案2
我们考虑用dp[i][j]表示已经处理了前i个物品,现在背包里的物品重量之和不大于j的情况下所能获得的最大物品价值之和。
状态转移方程:
dp[i][j] = max(dp[i-1][j], dp[i- 1][j-wi]+vi)
dp[i-1][ij]:表示不选第i个物品。
dp[i- 1][j-wi]+vi:表示选第i个物品。
//递推解决
for(int i=0;i<=W;i++) dp[0][i]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=W;j++)
{
d[i][j]= dp[i-1][j];
if(j>=w[i])
dp[i][j]=max(dp[i][j],dp[i-1][j-w[i]]+v[j]);
}
//answer=dp[n][W]
空间优化
使用滚动数组: cur表示当前层,last表示上一层
for(int j=0;j<=W;j++)cur[j]=0;
for(int i=1;i<=n;j++)
{
for(int j=0;j<=W;j++)
last[j]=cur[j],cur[j]=0;
for(int j=0;j<=W;j++)
{
cur[j]=last[j];
if(j>=w[i])
cur[j]=max(cur[j],last[j-w[i]);
}
}
// answer = cur[W]
无限背包
现在有n个物品,每个物品能取任意次,有一个背包,它所装物品重量之和不能超过W,第i个物品它的重量是wi,价值是vi, 现在的问题是,在不超过背包容量的限制下,最多能获得的物品价值之和是多少。
(1<=n<= 2000, 0<= W<= 2000, vi>0, wi> 0)
解决方案1
把无限背包问题转换成01背包问题,第i种物品最多有W / wi个起到作用,把每一种物品都拆成最多可能购买的数量,然后用01背包解决问题。最坏复杂度O(W* W * n)。
解决方案2
我们考虑用dp[i][j]表示已经处理了前i种物品,现在背包里的物品重量之和不大于j的情况下所能获得的最大物品价值之和。
状态转移方程:
dp[i][j]= max(dp[i-1[j], dp[i][j-wi]+vi)
dp[i-1][j]:表示不选第i种物品。
dp[i][j-wi]+vi :表示再选个第i种物品。
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
for(int j=w[i];j<=W;j++)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
//answer=dp[W]
多重背包
现在有n个物品,每个物品能取ci次,有一个背包,它所装物品重量之和不能超过W,第i个物品它的重量是wi,价值是vi, 现在的问题是,在不超过背包容量的限制下,最多能获得的物品价值之和是多少。
(1 <=n<= 2000, 0<= W<= 2000, vi>0, wi> 0)
解决方案1
把第i种物品拆成ci个,然后直接01背包求答案。
复杂度O(n * ci *W)
解决方案2
利用二进制拆分:
把最多能取ci个的物品拆分成:1,2,4,8, 16… 2^n , k 。
其中n是最大的满足1 +2 +4 +8 +16+ … + 2^n <= ci 的数。
k =ci -1 -2 -4 -8 -16 -… -2 ^n。
例子:
对于ci==7的物品,我们对于这种物品一共有8种决策,分别是选0, 1, 2, 3, 4, 5, 6, 7个。法1:拆成7个数量为1的物品(0000000-1111111)进行01背包就能得到这8种决策。 法2:如果把7拆分成数量为1个,2个,4个的三个物品(000-111),用这三个物品进行01背包也能覆盖上面这8种决策。
对于ci==12的物品,拆分成数量为1个,2个,4个,4个的物品(0000-1111),用这四个物品进行01背包(12<16)能覆盖0-12这13种决策。
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
{
int num;
for(num=1;num<=c[i];num*=2)
{
int cw=num*w[i];
int cv=num*v[i];
for(int j=W;j>=cw;j--)
dp[j]=max(dp[j], dp[j-cw]+cv);
c[i]-=num;
}
num=c[i];
if(num)
{
int cw=num*w[i];
int cv=num*v[i];
for(int j=W;j>=cw;j--)
dp[j]=max(dp[j],dp[j-cw]+cv);
}
}
状态压缩dp
概念
我们有多个物品,每个物品都有一个状态,我们用一个数字就去表示出所有物品的状态,这个就是状态压缩。简而言之就是把多个物品的状态压缩成一个数字。
举例
我们有4个物品,每个物品有两种状态分别是有和没有,我们用0表示没有,用1表示有。
高~>低 | 有的物品 | 没有的物品 |
---|---|---|
1010 | 1, 3 | 0, 2 |
0110 | 1, 2 | 0, 3 |
1011 | 0, 1, 3 | 2 |
对于一个压缩过后的十进制数S通过**(S>>i)& 1**获取到第i个物品的信息。 |
例如:S=10=1010 (二进制),想获取第1个物品的信息,(S>>1)=5=0101 (二进制),此时最低位就是一个物品的信息,所以(S>> 1) & 1就得到了第一个物品的信息。
简单例题
有n个城市,标号从0到n- 1,现在知道了每两个城市之间的距离,第i个城市和第j个城市之间的距离为d [i][j],现在有一个人想从0号城市开始把所有城市至少走一遍需要走多少距离。
(1 <=n<= 20, d[i][j]> 0)
解题思路
枚举所有的方案,只需要枚举1到n-1的全排列就可以,对于每一种方案计算一遍距离。时间复杂度O( (n- 1)! )
深入思考:对于所有经过城市相同,最后-一个到达城市也相同的情况,我们只需要保留距离最小的那个就可以了。
如果一共有5个城市,分别是0, 1, 2, 3, 4考虑这两种情况
0->1->3->2 | 距离=10 | (1) 这条路径不需要扩展了 |
---|---|---|
0->3->1->2 | 距离= 9 | (2) |
dp[i][mask] : 经过城市的情况是mask,最后停在i的最短距离
状态转移方程: dp[i][S] = max(dp[j][S^(1<<i)) 满足(S>>j& 1)== 1 &&j!= i
复杂度0 (n* (2 ^(n-1)))
for(int mask=0;mask<(1<<n);mask++)
for(int i=0;i<n;i++)
dp[j][mask]=inf;
dp[0][1]=0;
for(int mask=0;mask<(1<<n);mask++)
for(int i=0;i<n;i++)
if(mask>>i&1)
for(int j=0;j<n;j++)
if(j!=i&&mask>>j&1)
dp[i][mask]=min(dp[i][mask],dp[j][mask^(1<<i)]);
边栏推荐
- MATLAB图形加标注的基本方法入门简介
- Golang 垃圾回收机制详解
- PHY6222蓝牙5.2支持MESH组网M0内核超低功耗
- CI24R1小模块2.4G收发模块无线通信低成本兼容si24r1/XN297超低功耗
- Mysql的锁
- Lightweight AlphaPose
- 推开机电的大门《电路》(一):电压,电流,参考方向
- FP6296锂电池升压 5V9V12V内置 MOS 大功率方案原理图
- Please make sure you have the correct access rights and the repository exists. Problem solved
- win10怎么设置不睡眠熄屏?win10设置永不睡眠的方法
猜你喜欢
随机推荐
IPV4和IPV6是什么?
Detailed explanation of RecyclerView series article directory
define #使用
Makefile容易犯错的语法
Mysql连接错误解决
How to update Win11 sound card driver?Win11 sound card driver update method
机器学习和深度学习中的梯度下降及其类型
基于最小二乘法的线性回归分析方程中系数的估计
Win7怎么干净启动?如何只加载基本服务启动Win7系统
What is Win10 God Mode for?How to enable God Mode in Windows 10?
FP6195耐压60V电流降压3.3V5V模块供电方案
总结计算机网络超全面试题
GMP scheduling model of golang
LeetCode2 电话号码的字母组合
7. How to add the Click to RecyclerView and LongClick events
STM32F1和F4的区别
2021-10-14
How to solve Win11 without local users and groups
使用 腾讯云搭建一个个人博客
A clean start Windows 7?How to load only the basic service start Windows 7 system