关于背包,我相信任何一个对OI小有涉猎的人都有所耳闻,在NOIP前夕,特将各类基础背包模板整理后呈现于此,以供OIer们能有所便利。
首先介绍一下背包问题的类型,背包问题大致分为三类:01背包,完全背包,多重背包。
其中01背包是基础中的基础,几乎任何背包类问题的状态转移方程都是由01背包延伸而来的。它的大致题意是:有n个物品,每个物品有一个价值w[i],和重量c[i]。然后你的背包载重量是有限的V,因此需要选择总价值尽量大的物品。
而完全背包则是01背包的强化版——每个物品都有无限个了,再做出选择。而多重背包则更进一步:每个物品是有限多的个数,以此做出抉择。
在本文中并不会详细分析背包问题及其状态转移方程,仅仅是给出实现的模板,读者可以根据需要自由改动。关于背包类更详细的解答,可以在本文末的链接中下载由崔添翼(Tianyi Cui)所著的背包问题九讲中细细品味。
// 以下实现均使用了滚动数组技巧
void ZeroOnePack(int D[],int w,int c) //01背包,三个参数分别代表DP数组,物品价值,物品重量,V代表背包容量,以下相同
{
for(int i = V;i >= c;i--)
D[i] = max(D[i],D[i-c]+w);
}
void CompletePack(int D[],int w,int c) //完全背包
{
for(int i = c;i <= V;i++)
D[i] = += D[i-1];
}
void CompletePack_solutions(int D[],int w,int c) //求在完全背包的题设下,有多少种方法可以装满背包
{
for(int i = c;i <= V;i++)
D[i] = max(D[i],D[i-c]+w);
}
void MultiplePack(int D[],int w,int c,int num) //多重背包,num代表物品数目
{
if(c * num >= V)
{
CompletePack(D[],w,c);
return ;
}
int k = 1;
while(k < num)
{
ZeroOnePack(D[],w*k,c*k);
num -= k;
k *= 2;
}
ZeroOnePack(D[],w*num,c*num);
return ;
}
//以01背包为例,在主程序中,可以写出如下代码
for(int i = 1;i <= n;i++)
ZeroOnePack(D,w[i],c[i]);
《背包问题九讲》链接:http://pan.baidu.com/s/1qW9Hed2(若链接失效请及时提醒)