51Nod 1086 背包问题 (逐步加强版) 【背包/dp】

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 }
View Code

 

 

 

 

附加题: 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\n",ansp,answ);
54     return 0;
55 }
View Code

 

 

 

加油加油加油!!!fighting fighting fighting!!!

 

 

posted on 2018-07-15 15:49  Frank-King  阅读(310)  评论(0)    收藏  举报