背包专题
//这里使用f[N][N]作为dp的数组
/*val[N]表示价值,w[N]表示体积*/
typedef struct node
{
int val;//价值
int w;//体积
}bao;
一.01背包
01背包特点:每个物品只放一次
1.朴素写法
//模板
const int n=1003;
int f[N][N],val[N],w[N];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=v;j++)
{
if(j<w[i])
f[i][j]=f[i-1][j];
else
f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+val[i]);
}
}
2.空间优化
const int n=1003;
int f[N],val[N],w[N];
for(int i=1;i<=n;i++)
{
for(int j=v;j>=w[i];j--)
f[j]=max(f[j],f[j-w[i]]+val[i]);
}
二.多重背包
多重背包:每个物品放置Mi次
思路:将多重背包转化成01背包。一件价值VALi,大小Wi的可放置Mi次的物品==Mi剑价值VALi,大小Wi的只取一次的物品。
1.朴素写法
const int n=1003;
int f[N],val[N],w[N];
for(int i=1;i<=n;i++)
{
for(int k=1;k<=m[i];k++)
{
for(int j=v;j>=w[i];j--)
f[j]=max(f[j],f[j-w[i]]+val[i]);
}
}
展开表达
const int N=1003;
int f[N],val[N],w[N],m[N];
int val1[N],w1[N];
int n1=0;//新值,用来表达转化后的数值
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m[i];j++)
{
n1++;
w1[n1]=w[i];
val1[n1]=val[i];
}
}
for(int i=1;i<=n1;i++)
{
for(int j=v;j>=w[i];j--)
{
f[j]=max(f[j],f[j-w1[i]]+val1[i]);
}
}
2.二进制优化
展开表达
const int N=1003;
int f[N],val[N],w[N],m[N];
int val1[N],w1[N];
int n1=0;//新值,用来表达转化后的数值
for(int i=1;i<=n;i++)
{
for(int j=1;m[i];j<<=1)
{
j=min(j,m[i]);
m[i]=m[i]-j;
n1++;
w1[n1]=w[i]*j;
val1[n1]=val[i]*j;
}
}
for(int i=1;i<=n1;i++)
{
for(int j=v;j>=w[i];j--)
{
f[j]=max(f[j],f[j-w1[i]]+val1[i]);
}
}
朴素写法
const int n=1003;
int f[N],val[N],w[N];
for(int i=1;i<=n;i++)
{
for(int k=1;m[i];k<<1)
{
k=min(k,m[i]);
m[i]=m[i]-k;
for(int j=v;j>=w[i];j--)
f[j]=max(f[j],f[j-k*w[i]]+k*val[i]);
}
}
三.完全背包
特点:每件物品可以无限次存放
1.转化为多重背包
Mi=V/Ci
2.逆序循环01背包
const int n=1003;
int f[N],val[N],w[N];
for(int i=1;i<=n;i++)
{
for(int j=w[i];j<=v;j++)
f[j]=max(f[j],f[j-w[i]]+val[i]);
}