普通的完全背包我们都会,但是要是背包的容量炒鸡大,dp数组开不下怎么办呢?下面敬上超大完全背包模板一份。
大闹上兰帝国
时间限制: C/C++ 20000ms; Java 40000ms 内存限制: 65535KB
通过次数: 9 总提交次数: 20
![](http://acm.nuc.edu.cn/OJ/image/ac.png)
问题描述
由于zbt日常搞事情,早已弄得上兰帝国天翻地覆。于是很快被SHlong列入了上兰帝国重点教育对象,zbt作为一个不受驯服的人当然要奋起反抗了,于是他开始四处破坏,SHlong由于能力有限不能降服zbt,于是只能去ACM实验室请来了声望极高的Wukan方丈,Wukan方丈对zbt说:“听说你十分擅长传说中的背包问题,那么我就出一个完全背包,你若是答得出来就让你随便搞事情。你要是答不出来,那我就要把你赶出上兰帝国了”。zbt当然随口答应了,于是Wukan方丈就开始出题了。
有一个容量为S的背包,和N种物品,每种物品都有一个体积和价值,每种物品可以无限使用。求容量不超过S的情况下价值的能放入背包的最大价值。
zbt看了下题嘲讽道:“这不是一道大水题吗”,话音未落,他突然发现貌似存在一些小(很大的)问题。于是他偷偷的使用传音之术来请你帮助他来解决这个问题。
输入描述
输入包含多组数据
每组数据第一行有两个正整数N,S分别代表物品的种类和背包的容量。
后面N行每行两个数v,w代表每种物品的体积和价值。
1<=N,v<=1000;
0<=S,w<=1000000000;
输出描述
对于每组数据分别输出一行,每行只有一个正整数,代表可以放入的最大的价值。
样例输入
3 100 14 5 13 2 5 1
样例输出
35
来源
第三届山西省大学生程序设计大赛
#include <iostream>
#include <cstdio>
#include <cstring>
#define me(x,y) memset(x,y,sizeof(x))
#define sd(x) scanf("%d",&x)
#define ss(x) scanf("%s",x)
#define sf(x) scanf("%f",&x)
#define slf(x) scanf("%lf",&x)
#define slld(x) scanf("%lld",&x)
#define pd(x) printf("%d\n",x)
#define plld(x) printf("%lld\n",x)
#define ps(x) printf("%s\n",x)
#define max(x,y) (x>=y?x:y)
#define min(x,y) (x<y?x:y)
#define sum(x,y) (x+y)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=1005;
ll n,c;
ll dp[maxn*5];
ll dp2[55][maxn*5];
ll w[maxn],v[maxn];
ll low[50];
void init() {
me(dp,0);
me(dp2,0);
me(low,0);
}
int main() {
while(scanf("%lld%lld",&n,&c)!=EOF) {
ll maxv=0;
for(int i=1;i<=n;i++) {
slld(v[i]);
slld(w[i]);
maxv=max(maxv,v[i]);
}
init();
ll s=c;
ll cnt=0;
while(s>0){
low[++cnt]=s;
s=((s-maxv)>>1);
}
for(ll i=1;i<=n;i++)
for(ll j=v[i];j<=maxv*4;j++)
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
for(ll i=cnt;i>=1;i--){
for(ll j=low[i];j<=low[i]+maxv*2;j++){
if(j<=4*maxv) dp2[i][j-low[i]]=dp[j];
else{
for(ll k=(j-maxv)/2;k<=j/2;k++) //下一层
dp2[i][j-low[i]]=max(dp2[i][j-low[i]],dp2[i+1][k-low[i+1]]+dp2[i+1][j-k-low[i+1]]);
}
}
}
plld(dp2[1][0]);
}
return 0;
}