15
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3732
解法类型:贪心+01背包 || 多重背包
解题思路:乍一看是很典型的01背包问题,但一看数据,01背包的复杂度O(N*V)对于这题来说肯定会超时,而且01背包要优化也只能是常数级。我们注意到01背包方程:d[v]=max{d[v],d[v-cost]+weight};d[v]存储的是前i个物品在最大容量V下所能获得的最大价值。再仔细看题目,注意这个条件0 ≤ Vi , Ci ≤ 10。由于vi和ci都在很小的范围内,所以可以用贪心的思想先求出当单词复杂度不超过C-10时的最大价值,假设此时为Cmax,这样D[Cmax]是最大的。然后用01背包求出剩下的容量Cmax-C所能取得的最大价值,最后相加即可。显然,时间复杂度几乎是线性的!
当然这题也可以优化为多重背包来求解,同样注意0 ≤ Vi , Ci ≤ 10,所以N最大为100,时间复杂度也不是很高。
算法实现:
贪心+01背包:
//STATUS:C++_AC_187MS_1008KB #include<stdio.h> #include<stdlib.h> #include<string.h> const int MAX=100010; int cmp(const void* a,const void* b); struct NUM { int v,c; }num[MAX]; int N,C,d[20]; int main() { // freopen("in.txt","r",stdin); int i,ansv,ansc,lc,c,t; char ch[20]; while(~scanf("%d%d",&N,&C)) { memset(d,0,sizeof(d)); for(i=0;i<N;i++) scanf("%s%d%d",ch,&num[i].v,&num[i].c); qsort(num,N,sizeof(NUM),cmp); ansv=ansc=0; for(i=0;i<N;i++){ ansv+=num[i].v; ansc+=num[i].c; if(C-ansc<10){ ansv-=num[i].v; ansc-=num[i].c; break; } } if(i<N){ for(lc=C-ansc;i<N;i++){ for(c=lc;c>=num[i].c;c--){ t=d[c-num[i].c]+num[i].v; if(t>d[c])d[c]=t; } } ansv+=d[lc]; } printf("%d\n",ansv); } return 0; } int cmp(const void* a,const void* b) { int v1=((NUM*)a)->v,c1=((NUM*)a)->c, v2=((NUM*)b)->v,c2=((NUM*)b)->c; if(v1*c2>v2*c1)return -1; else if(v1*c2<v2*c1)return 1; else return 0; }
//STATUS:C++_AC_171MS_268KB #include<stdio.h> #include<string.h> const int MAX1=10010,MAX2=110; void cpack(int cost,int weight); void zopack(int cost,int weight); int map[11][11],d[MAX1],N,C,vc[MAX2][2],n[MAX2],nup[MAX2]; int main() { // freopen("in.txt","r",stdin); int i,k,v,c,t; char ch[20]; while(~scanf("%d%d",&N,&C)) { memset(map,0,sizeof(map)); memset(d,0,sizeof(d)); for(i=0;i<N;i++){ scanf("%s%d%d",ch,&v,&c); map[v][c]++; } for(k=0,v=1;v<11;v++) for(c=1;c<11;c++) if(map[v][c]) vc[k][0]=v,vc[k][1]=c, n[k]=map[v][c],nup[k++]=C/c; N=k; for(i=0;i<N;i++){ if(n[i]>=nup[i]) cpack(vc[i][1],vc[i][0]); else { t=n[i]; for(k=1;k<t;){ zopack(k*vc[i][1],k*vc[i][0]); t-=k; k*=2; } zopack(t*vc[i][1],t*vc[i][0]); } } printf("%d\n",d[C]); } return 0; } void cpack(int cost,int weight) { int c,t; for(c=cost;c<=C;c++) if((t=d[c-cost]+weight)>d[c])d[c]=t; } void zopack(int cost,int weight) { int c,t; for(c=C;c>=cost;c--) if((t=d[c-cost]+weight)>d[c])d[c]=t; }