51Nod 1085~1087 背包问题
第一种:
最基本的 n*w ,f[i][j] (j>=w[i]) = max(f[i-1][j] , f[i-1][j-w[i]+p[i] ); 数组还可以用滚动压成一维。
代码不贴,度娘慷慨!
第二种:
多重背包。加了一维物品数。直接做多枚举一维物品数,数据大要T掉。所以我们采用一种优化叫二进制分解。
就是把一个物品的个数拆成二进制,然后把每组 2^i 个物品组合在一起看成单独的一个物品,这样我们就实现了把多重背包转换成 01背包了。 剩下的直接按上面的做就可以了。。
代码:
1 #include<bits/stdc++.h> 2 #define LL long long 3 using namespace std; 4 const int W=5*1e4; 5 int n,w,f[W+10],two[10]; 6 int main() 7 { 8 scanf("%d%d",&n,&w); 9 two[0]=1; 10 for (int i=1; i<=7; i++) two[i]=two[i-1]*2; 11 for (int k=1; k<=n; k++) 12 { 13 int ww,p,c,ii=0; scanf("%d%d%d",&ww,&p,&c); 14 for (int i=0; i<=7; i++) 15 if (c>=two[i]) 16 { 17 for (int j=w-ww*two[i]; j>=0; j--) 18 f[j+ww*two[i]]=max(f[j+ww*two[i]],f[j]+p*two[i]); 19 c-=two[i]; 20 } 21 else break; 22 for (int i=7; i>=0; i--) 23 if (c>=two[i]) 24 { 25 for (int j=w-ww*two[i]; j>=0; j--) 26 f[j+ww*two[i]]=max(f[j+ww*two[i]],f[j]+p*two[i]); 27 c-=two[i]; 28 } 29 } 30 int ans=0; 31 for (int i=1; i<=W; i++) ans=max(ans,f[i]); 32 cout<<ans<<endl; 33 return 0; 34 }
附加题: 51Nod 1257
N个物品的体积为W1,W2......Wn(Wi为整数),与之相对应的价值为P1,P2......Pn(Pi为整数),从中选出K件物品(K <= N),使得单位体积的价值最大。
Input
第1行:包括2个数N, K(1 <= K <= N <= 50000)
第2 - N + 1行:每行2个数Wi, Pi(1 <= Wi, Pi <= 50000)
Output
输出单位体积的价值(用约分后的分数表示)。
Input示例
3 2
2 2
5 3
2 1
Output示例
3/4
看似是背包,其实否然。
这题只需二分一下就可以了。二分单位体积的价值 p,然后设每个物品的 rate 为 w[i]-p*p[i],按 rate 从大到小排序,
然后去最大的 k 个,如果最后的rate 之和大于0,那么说明 p 还能再大,否则 p 只能变小。
代码:
1 #include<bits/stdc++.h> 2 #define LL long long 3 using namespace std; 4 const int maxn=50007; 5 LL gcd(LL a,LL b) { return b==0?a:gcd(b,a%b); } 6 int n,k; 7 struct node{ 8 int w,p; 9 double rate; 10 }beg[maxn]; 11 bool cmp(node a,node b) 12 { 13 return a.rate>b.rate; 14 } 15 int resw,resp; 16 int answ,ansp; 17 bool check(double p) 18 { 19 resw=0; 20 resp=0; 21 double mark=0.0; 22 for (int i=1; i<=n; i++) 23 beg[i].rate=1.0*beg[i].p-beg[i].w*p; 24 sort(beg+1,beg+1+n,cmp); 25 for (int i=1; i<=k; i++) 26 { 27 resw+=beg[i].w; 28 resp+=beg[i].p; 29 mark+=beg[i].rate; 30 } 31 if (mark>=0) return true; 32 return false; 33 } 34 int main() 35 { 36 scanf("%d%d",&n,&k); 37 for (int i=1; i<=n; i++) 38 scanf("%d%d",&beg[i].w,&beg[i].p); 39 double l=0.0,r=50000; 40 for (int i=0; i<=100; i++) 41 { 42 double mid=(l+r)/2; 43 if (check(mid)) 44 { 45 answ=resw; 46 ansp=resp; 47 l=mid; 48 } 49 else r=mid; 50 } 51 LL gg=gcd(answ,ansp); 52 answ/=gg; ansp/=gg; 53 printf("%d/%d ",ansp,answ); 54 return 0; 55 }
加油加油加油!!!fighting fighting fighting!!!