看了一上午背包,整理的成果
背包问题
问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。
初始化
如果要求恰好装满背包,那么在初始化时除了f[0]为0其它f[1..V]均设为-∞
如果要求价格尽量最大,初始化时应该将f[0..V]全部设为0
1.0-1背包问题:最基本的背包问题,每个物品最多只能放一次。
for i=1..n
for v=V..0
f[v]=max{f[v],f[v-w[i]]+c[i]};
//01背包
void ZeroOnePack(int c, int w)
{for (int v = V; v >= c; v--)
{dp[v] = max(dp[v], dp[v - c] + w);}}
2.完全背包问题:基本的背包问题模型,每种物品可以放无限多次。
for i=1..N
for v=0..V
f[v]=max{f[v],f[v-weight]+cost}
思路:将第i种物品拆成费用为w[i]*2^k、价值为c[i]*2^k的若干件物品,其中k满足w[i]*2^k<=V
//完全背包
void CompletePack(int c, int w)
{for (int v = c; v <= V; v++)
{ dp[v] = max(dp[v], dp[v - c] + w);}}
3.多重背包问题:每种物品有一个固定的次数上限。
for(i=1;i<=N;i++)//N种物品
for(j=V;j>=0;j--)//容量为V
for(k=0;k<=num[i];k++)//每种物品最多有num[i]个
if(j-k*w[i]>=0)//当前容量-k个物品的重量>=0
f[j]=max(f[j],f[j-k*w[i]]+k*c[i]);
//多重背包
void MultiplePack(int c, int w, int num)
{ if (c * num >= V)
{CompletePack(c, w);}
else{
int k = 1;
while (k < num){
ZeroOnePack(k*c, k*w);
num -= k;
k <<= 1;}
ZeroOnePack(num*c, num*w);}}
4.混合三种背包问题:将前三种的问题叠加成较复杂的问题。
【01背包与完全背包的混合】
for i=1..N
if 第i件物品是01背包(只取一次时)
for v=V..0
f[v]=max{f[v],f[v-w[i]]+c[i]};
else if 第i件物品是完全背包(可以取无限多时)
for v=0..V
f[v]=max{f[v],f[v-w[i]]+c[i]};
【加上多重背包】
for i=1..N
if 第i件物品是01背包(只取一次时)
ZeroOnePack(c[i],w[i])
else if 第i件物品是完全背包(可以取无限多时)
CompletePack(c[i],w[i])
else if 第i件物品是多重背包(有固定取的次数时)
MultiplePack(c[i],w[i],n[i])
5.二维费用的背包问题:费用增加了一维。
问题:对于每件物品,具有两种不同的体积,选择这件物品必须同时付出这两种代价,对于每种代价都有一个可付出的最大值(背包容量)。
for (int i=0; i<=V; i++) // 边界
for (int j=0; j<=U; j++)
s[i][j]=0;
for (int i=1; i<=N; i++)
for (int j=V; j>=v[i]; j--)
for (int k=U; k>=u[i]; k--)
s[j][k]=max(s[j][k], s[j-v[i]][k-u[i]]+c[i]);
6. 分组的背包问题:对于每件物品,具有两种不同的费用;选择这件物品必须同时付出这两种代价。
问题:有N件物品和一个容量为V的背包。第i件物品的体积w[i],价值是c[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。
for 所有的组k
for v=V..0
for 所有的i属于组k
f[v]=max{f[v],f[v-w[i]]+c[i]}
7.有依赖的背包问题:给物品的选取加上限制的方法。
问题:背包问题的物品间存在某种“依赖”的关系,也就是说,i依赖于j,表示若选物品i,则必须选物品j。
下午比赛时一直不在状态,可能是刚吃饱饭,或者中午没休息,还是说自己就是心不在焉的,水了一下午,很对不起我的两位队友,我一定认真整理资料,明天调整好状态。