说明:根据acwing算法提高课和算法基础课整理,代码根据y总的稍加修改。
问题模型描述:
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的体积是vi,价值是 wi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
模板题:2. 01背包问题 - AcWing题库
代码(空间优化版):
#include
using namespace std;
const int N=1010;
int f[N];
int main()
{
int n,m;
cin>>n>>m; //数量和总体积
for(int i=0;i>v>>w;
for(int j=m;j>=v;--j) f[j]=max(f[j],f[j-v]+w);
}
cout<
问题模型描述:0-1背包问题的基础上,每一个物品可以无限选用。
模板题:3. 完全背包问题 - AcWing题库
代码(优化到O(n^2),空间一维):
#include
using namespace std;
const int N=1010;
int f[N];
int main()
{
int n,m;
cin>>n>>m; //数量和总体积
for(int i=0;i>v>>w;
for(int j=v;j<=m;++j) f[j]=max(f[j],f[j-v]+w);
}
cout<
问题模型描述:
有 N 组物品和一个容量是 V 的背包。每组物品有若干个,同一组内的物品最多只能选一个。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
模板题:9. 分组背包问题 - AcWing题库
代码:
#include
using namespace std;
const int N=110;
int f[N],v[N][N],w[N][N],s[N];
int main()
{
int n,m;
cin>>n>>m; //数量和总体积
for(int i=1;i<=n;++i){
cin>>s[i]; //第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(v[i][k]<=j) f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);
cout<
这个不算背包模型,算是区间dp,朴素做法复杂度是O(n^3),这里贴上O(n^2)复杂度的代码。
问题模型描述:两个数列 A 和 B,如果它们都包含一段位置不一定连续的数,且数值是严格递增的,那么称这一段数是两个数列的公共上升子序列,而所有的公共上升子序列中最长的就是最长公共上升子序列。
模板题:272. 最长公共上升子序列 - AcWing题库
代码(O(n^2)):
#include
using namespace std;
const int N=3010;
int n,a[N],b[N],f[N][N];
int main()
{
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=n;++i) cin>>b[i];
for(int i=1;i<=n;++i){
int maxv=1;
for(int j=1;j<=n;++j){
f[i][j]=f[i-1][j];
if(a[i]==b[j]) f[i][j]=max(f[i][j],maxv);
if(b[j]
问题模型描述:0-1背包问题的基础上,最优选法的方案数。
模板题:11. 背包问题求方案数 - AcWing题库
代码:
#include
using namespace std;
const int N=1010,mod=1e9+7;
int f[N],g[N];
int main()
{
int n,m;
cin>>n>>m;
g[0]=1;
for(int i=0;i>v>>w;
for(int j=m;j>=v;--j){
int mav=max(f[j],f[j-v]+w),cnt=0;
if(mav==f[j]) cnt+=g[j];
if(mav==f[j-v]+w) cnt+=g[j-v];
cnt%=mod;
g[j]=cnt;
f[j]=mav;
}
}
int res=0,ans=0;
for(int i=0;i
问题模型描述:有 N 个物品和一个容量是 V 的背包。物品之间具有依赖关系,且依赖关系组成一棵树的形状。如果选择一个物品,则必须选择它的父节点。
模板题:10. 有依赖的背包问题 - AcWing题库
状态表示:f[u][m]:以u为根节点的子树,在代价不超过m时产生的最大价值。
#include
using namespace std;
const int N=110;
int h[N],ne[N],e[N],idx,v[N],w[N],f[N][N];
int n,m;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u)
{
for(int i=h[u];~i;i=ne[i]){
int son=e[i];
dfs(son);
for(int j=m-v[u];j>=0;--j)
for(int k=0;k<=j;++k)
f[u][j]=max(f[u][j],f[u][j-k]+f[son][k]);
}
for(int i=m;i>=v[u];--i) f[u][i]=f[u][i-v[u]]+w[u];
for(int i=0;i>n>>m;
memset(h,-1,sizeof(h));
int r;
for(int i=1;i<=n;++i){
int p;
cin>>v[i]>>w[i]>>p;
if(p==-1) r=i;
else add(p,i);
}
dfs(r);
cout<
问题模型描述:0-1背包问题的基础上,第i个物品最多选择si件。
模板题:5. 多重背包问题 II - AcWing题库
代码(二进制优化版):
#include
using namespace std;
const int M=2010,N=25000;
int v[N],w[N],f[M];
int main()
{
int n,m;
cin>>n>>m;
int cnt=0;
for(int i=1;i<=n;++i){
int a,b,s;
cin>>a>>b>>s;
int k=1;
while(k<=s){
++cnt;
v[cnt]=a*k,w[cnt]=b*k;
s-=k;
k<<=1;
}
if(s>0){
++cnt;
v[cnt]=a*s,w[cnt]=b*s;
}
}
n=cnt;
for(int i=1;i<=n;++i)
for(int j=m;j>=v[i];--j)
f[j]=max(f[j],f[j-v[i]]+w[i]);
cout<
滑动窗口优化版:
#include
using namespace std;
const int N=20010;
int f[N],g[N],q[N];
int main()
{
int n,m;
cin>>n>>m;
for(int i=0;i>v>>w>>s;
memcpy(g,f,sizeof(f)); //存上一层状态
for(int j=0;j
问题模型描述:有 N 种物品和一个容量是 V 的背包。
物品一共有三类:
模板题:7. 混合背包问题 - AcWing题库
代码:
#include
using namespace std;
const int N=1010;
int n,m;
int f[N];
int main()
{
cin>>n>>m;
for(int i=0;i>v>>w>>s;
if(s==0) //完全背包
for(int j=v;j<=m;++j) f[j]=max(f[j],f[j-v]+w);
else{
if(s==-1) s=1; //01背包相当于个数为1的多重背包
for(int k=1;k<=s;k*=2){
for(int j=m;j>=k*v;--j) f[j]=max(f[j],f[j-k*v]+k*w);
s-=k;
}
if(s) for(int j=m;j>=s*v;--j) f[j]=max(f[j],f[j-s*v]+s*w);
}
}
cout<