SPOJ 699 HKNAP - Huge Knap Sack

来源:互联网 发布:淘宝团队管理 编辑:程序博客网 时间:2024/06/05 16:41

部分贪心解决大背包问题

先利用数据特殊性将物品压缩成18个,第i个体积是i,重量为w[i],这里w[i]取体积为i的原物品的最大值。

然后找到性价比最大的wi,vi。

考虑任意一个物品p,若取q个该物品且q>=vi,即q=vi+x(x>=0),则总重量为w[p]*(vi+x)

w[p]*(vi+x)=w[p]*vi+w[p]*x<wi*vi+w[p]*x。于是对于任意性价比不为wi,vi的物品,qi<vi。

所以取limit=vi*18,即每个物品都取18个,则容量为k时的最优解可以表示为

令t=(k-limit)/vi(上取整,原论文的下取整不对)

weight(k)=t*wi+f[k-t*vi]。

f可以先DP出来。

然后再做一遍背包,即对合并进行DP,此时令w[i]=weight(i*y)-(i-1)*c,v[i]=i,论文中S为10^9,再次套用刚才的方法求解。

当然题目中S<=1000,可以直接求解。

#include<iostream>#include<cstring>#include<cstdio>using namespace std;typedef long long ll;int wi,vi,lim;ll f[1005],w[405];ll weight(ll k){ll t=(k-lim)/vi;if((k-lim)%vi)t++;return t*wi+f[k-t*vi];}int main(){//freopen("a.in","r",stdin);//freopen("a.out","w",stdout); int T;scanf("%d",&T);while(T--){int s,y,n,c;scanf("%d%d%d%d",&n,&s,&y,&c);memset(w,0,sizeof(w));for(int i=1;i<=n;i++){int a,b;scanf("%d%d",&a,&b);w[b]=max(w[b],(ll)a);}wi=w[1],vi=1;for(int i=1;i<=18;i++)if(w[i]*vi>wi*i)wi=w[i],vi=i;lim=18*vi;memset(f,0,sizeof(f));for(int i=1;i<=18;i++)for(int j=i;j<=lim;j++)f[j]=max(f[j],f[j-i]+w[i]);ll t=(y-lim)/vi;for(int i=1;i<=lim;i++)f[i]=max(f[i],f[i-1]);for(int i=1;i<=lim;i++)w[i]=weight((ll)y*i)-c*(i-1);memset(f,0,sizeof(f));for(int i=1;i<=lim;i++)for(int j=i;j<=s;j++)f[j]=max(f[j],f[j-i]+w[i]);printf("%lld\n",f[s]);}return 0;}


这么水的题我废话半天干嘛。。。。。。。。

0 0
原创粉丝点击