01背包问题
题目
解释
【动态DP】01背包问题_nathanqian123的博客-CSDN博客
代码段
算法一(二维数组)
#include<iostream>
const int N=1010;
int n,m;
int w[N],v[N];
int dp[N][N];
using namespace std;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>v[i]>>w[i];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
//这里j从1开始,
//因为当空间大小为0时,因为无法选择任何物品
{
dp[i][j]=dp[i-1][j];//如果不选择当前物品
if(j-v[i]>=0)
//如果选择且当前背包容量足够的话
//选择当前物品相当于在没选择时的总空间大小j-v[i]情况下加上了w[i]
//占用空间v[i]
dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]);
}
cout<<dp[n][m]<<endl;
}
算法二(一维优化)
#include<iostream>
using namespace std;
const int N=1010;
int f[N],v[N],w[N];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
for(int i=1;i<=n;i++)
for(int j=m;j>=v[i];j--)
//如果j正序,则可能下标较小的先更新,那么这时就不是上一轮的f[j]了
{
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
cout<<f[m]<<endl;
return 0;
}
完全背包问题
题目
解释
- 因为每个物品可以选择无限件,所以我们决策使用一个物品时,需要考虑它的件数
- 因此表达式为第一个公式的形式
- 再观察第二个表达式f[i,j-v]的形式,与第一个只相差一个w[i]
- 因此递推关系可以表示成
- f(i,j)=max(f(i,j-v)+w,f(i-1,j);
代码段
#include<iostream>
using namespace std;
const int N=1010;
int f[N][N],v[N],w[N];
int n,m;
int main()
{
cin>>n>>m;
for(int i=1;i<n;i++)
cin>>v[i]>>w[i];
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
{
f[i][j]=f[i-1][j];
if(j>=v[i])
f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);
}
cout<<f[n][m]<<endl;
}
多重背包问题I
题目
AcWing 4. 多包 I(一看就会,懒人专用)+saber精简代码 - AcWing
解释
- 将多个同一件物品看成不同的物品进行v*s次决策
代码段
算法一(拆包成01背包问题)
#include<iostream>
using namespace std;
const int N=10010;
int V,W,S,v[N],w[N];
int f[N];
int n,m,t;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>V>>W>>S;
while(S--)
{
v[++t]=V;
w[t]=W;
}
}
for(int i=1;i<=t;i++)
for(int j=m;j>=v[i];j--)
{
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
cout<<f[m]<<endl;
}
多重背包问题II(二进制优化)
题目
解释
- 可以直接参考如上题解
- 需要思考的问题是
- 二进制为何可以对s进行优化,如何用二进制取代一一枚举
- 二进制怎样合理的划分一个数,以及代码如何实现二进制对整数的划分
- DP是如何对二进制后1 2 4....进行决策,怎样保证最优解
- 参考01背包问题的决策方式
代码段
#include<iostream>
using namespace std;
const int N=1e5;
int V,W,S,v[N],w[N];
int f[N];
int n,m,t;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>V>>W>>S;
for(int j=1;j<=S;j*=2)
{
S-=j;
v[++t]=V*j;
w[t]=W*j;
}
if(S>0)
{
v[++t]=V*S;
w[t]=W*S;
}
}
for(int i=1;i<=t;i++)
for(int j=m;j>=v[i];j--)
{
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
cout<<f[m]<<endl;
}
分组背包问题
题目
解释
- 三层循环暴力DP
代码段
#include<iostream>
using namespace std;
int n,m;
const int N=200;
int v[N][N],w[N][N],s[N],f[N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>s[i];
for(int j=1;j<=s[i];j++)
cin>>v[i][j]>>w[i][j];
}
for(int i=1;i<=n;i++)
{
for(int j =m;j>=0;j--)
for(int k=1;k<=s[i];k++)
{
if(j>=v[i][k])f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);
}
}
cout<<f[m]<<endl;
}