码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 2191 悼念汶川地震(AC代码)多重背包

时间:2015-01-19 12:31:34      阅读:129      评论:0      收藏:0      [点我收藏+]

标签:

0MS  1084K  706B  C++

这是用“转01背包”实现的,速度还这么快,还需优化不?

技术分享
 1 # include <stdio.h>
 2 # include <string.h>
 3 int dp[101] ;//转成01背包的解法,没有任何优化。
 4 int max(int a,int b)
 5 {
 6     return a>b?a:b;
 7 }
 8 int main ()
 9 {
10     int T, ans, n, m ;
11     int p, h, c, i, j ;
12     scanf ("%d", &T) ;
13     while (T--)
14     {
15         scanf ("%d%d", &n, &m) ;    //n是经费,m是种类
16         memset (dp, 0, sizeof(dp)) ;
17         ans = 0 ;
18         while (m--)
19         {
20             scanf ("%d%d%d", &p, &h, &c) ;
21             for(i = 1 ; i<=c ; i++)        //m是经费
22             {
23                 for(j = n ; j >= p ;j--)
24                 {
25                     dp[j]=max(dp[j],dp[j-p]+h);
26                 }
27             }
28         }
29         printf ("%d\n", dp[n]) ;
30     }
31     return 0 ;
32 }
2191

思路:多重背包转成01背包,怎么转?把一种大米看成一堆单个的物品,每件物品要么装入,要么不装。复杂度比01背包要大,假设每种大米有10件,那么在01背包的复杂度O(vn)的基础上,每种大米的计算量要乘以10,那么复杂度O(10*vn)。这是假设每种大米数量为10的情况,若为m,那么复杂度O(vnm),很大。这个做法太粗糙了,但就是AC了。

其他没实现的想法:按照完全背包的做法,在里面加一些东西来控制“数量不够”的情况。当数量已达上限,用做大数量来代替,那么需要比较的两个dp值就是dp[j]与dp[j-1],分别代表不装、装满。另用一个数组来记录每个不同的经费上限对应dp数组中所用的第i种大米的数量。这个数组要在不同i时更新为0,有开销。这个想法实现不了。

另外可行的思路:

在转成01背包上作优化。完全背包+01背包来解,即:某一种大米的数量*单价>=经费,那么就是完全背包型;否则就是01背包型。但如果遇到都是01背包型,此优化没用了。

②01背包+二进制法。 还没理解二进制的真谛,看到别人好像实现了。

③队列法。复杂度为O(vn),还没理解。

 

附件一:未实现的想法

技术分享
 1 #include <iostream>
 2 #define limit 110
 3 using namespace std;
 4 int p[limit];    //单价
 5 int h[limit];    //净重
 6 int c[limit];    //数量上限
 7 int u[limit];    //已买的数量
 8 int dp[limit];
 9 int max(int a,int b)
10 {
11     return a>b?a:b;
12 }
13 void cal(int n,int m)
14 {
15     int temp=0,j,i;
16     for(i=0;i<m;i++)
17     {
18         for(j=0;j<=n;j++)    //初始化数组u
19             u[j]=0;
20         for( j=p[i];j<=n;j++)
21         {
22             temp=max( dp[j],dp[j-p[i]]+h[i] );
23             if(temp==dp[j-p[i]]+h[i])    //需要加多一件
24             {
25                 if(u[j-p[i]]<c[i])    //第i件还有剩余,可以买。
26                 {
27                     u[j]=u[j-p[i]]+1;
28                     dp[j]=temp;
29                 }
30                 else    //被用光了,但是为了防止前大于后的情况,在不能追加的情况下,仍需比较前后的大小,保证后总大于前
31                 {
32                     dp[j]=max(dp[j-1],dp[j]);    //仅需比较1个,因前面每个所使用的并不是升序的,可能无序的
33                     if(dp[j]==dp[j-1])
34                         u[j]=u[j-1];//因为u[j]本来就是0,所以else的情况不用赋零
35                 }
36             }
37         }
38     }
39     return;
40 }
41 void main()
42 {
43     int q,n,m,i;
44     scanf("%d",&q);
45     while(q--)
46     {
47         memset(dp,0,sizeof(dp));
48         scanf("%d%d",&n,&m);    //经费的金额   大米的种类
49         for(i=0;i<m;i++)
50         {
51             scanf("%d%d%d",&p[i],&h[i],&c[i]);    //分别表示每袋的价格、每袋的重量以及对应种类大米的袋数
52         }
53         cal(n,m);
54         printf("%d\n",dp[n]);
55     }
56 }
2191

附件二:可行的思路①

技术分享
 1 #include<iostream>
 2 const int N=110;
 3 using namespace std;
 4 int n,m;
 5 
 6 struct Rice{
 7     int price;
 8     int weight;
 9     int number;
10 }rice[N];
11 int dp[N];
12 int max(int a,int b)
13 {
14     return a>b?a:b;
15 }
16 //完全背包
17 void CompletePack(int cost,int weight){
18     for(int i=cost;i<=n;i++){
19         dp[i]=max(dp[i],dp[i-cost]+weight);
20     }
21 }
22 //01背包
23 void ZeroOnePack(int cost,int weight){
24     for(int i=n;i-cost>=0;i--){
25         dp[i]=max(dp[i],dp[i-cost]+weight);
26     }
27 }
28 
29 //多重背包
30 void MultiplePack(int cost,int weight,int number){
31     //如果大于等于金额,就按完全背包处理(此时相当于不限定袋数)
32     if(cost*number>=n){
33         CompletePack(cost,weight);
34         return ;
35     }
36     int k=1;
37     while(k<number){
38         ZeroOnePack(k*cost,k*weight);
39         number-=k;
40         k*=2;
41     }
42     ZeroOnePack(number*cost,number*weight);
43 }
44 
45 int main(){
46     int _case;
47     scanf("%d",&_case);
48     while(_case--){
49         scanf("%d%d",&n,&m);
50         memset(dp,0,sizeof(dp));
51         for(int i=0;i<m;i++){
52             scanf("%d%d%d",&rice[i].price,&rice[i].weight,&rice[i].number);
53         }
54         for(i=0;i<m;i++){
55             MultiplePack(rice[i].price,rice[i].weight,rice[i].number);
56         }
57         printf("%d\n",dp[n]);
58     }
59     return 0;
60 }
2191

 

HDU 2191 悼念汶川地震(AC代码)多重背包

标签:

原文地址:http://www.cnblogs.com/xcw0754/p/4233379.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!