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

HDU 1712 ACboy needs your help AC男需要你的帮助 (AC代码)分组的背包问题

时间:2015-01-20 17:40:02      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:

分组的背包问题N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

HDU 1712AC男有m天时间可以上课,有n种课程可以选,但是每一种课程有各种的上课时长可选(因为并不是花的时间与收获就呈线性增长的,两者之间没什么对应关系,也许花1天收获2点经验,但是花2天就不是4点经验了,可能是3点而已)。耗时与收获以矩阵的方式给出。(把同一课程的不同授课时间看成是同一组背包的不同物品,物品件没联系)。

此题与分组的背包问题几乎一模一样,还帮你把同一组内的物品给排好序了,那么就可以稍微减少一点点计算时间了。

 

思路:类似于01背包,那就要转成01背包的思想。第1层循环是前 i “组”,第2层循环是当前背包容量(即m)为j,第3层循环是每种授课方式。说点容易懂的话,每组物品中只能选1件,那么有多少组就是多少件了,当然也可以不选,那么问题就是在第i组中装还是不装,若装,要装哪一件?

看伪码:

for 所有的组k  //组
    for v=V..0  //当前背包容量
        for 所有的i属于组k  //组内物品
            f[v]=max{f[v],f[v-c[i]]+w[i]}  //时刻要保证v-c[i]>=0,总不能让数组的下标为负数吧?


第3层循环都是在同一当前背包容量下在试探到底装哪一件比较合适。假如要试探第1组,当前背包容量为10,现在开始装第1组内的第1件物品,max(0,此物品的价值),那肯定是装进去更大啦。那就装了,第3个for再次循环,现在试探装不装第1组内的第2件物品,max(0,此物品的价值)。因为第1件已经装入,那么现在在做的工作就是“试试第2、3、4...件装进去是不是更合适”。在更新的都是dp[v]这一个值,当第2个for再次循环才是更新另一个dp值。
那么假如现在第1个for是k=7,即第7组,那么第2个for的v=10,假设背包容量10为上限,第3个for开始试探第1件,发现这一件不适合装入,即装入后收获更低了。开始试探第7组的第2件了。其实这时在做的依然是“第i组的物品该不该装入背包”。
由于类似于01背包,所以第2层循环要逆序的,即从大到小,第3层最好就是顺序的了,一旦判断出第5件已经装不下,那第6件就不用再试了。这是按照HDU1712解释的。

 

以下有几种AC的代码:

1、容易理解  78MS

技术分享
 1 #include <iostream>
 2 #define num 101
 3 using namespace std;
 4 int a[num][num];
 5 int dp[num];
 6 int max(int a,int b)
 7 {
 8     return a>b?a:b;
 9 }
10 void cal(int n,int m)
11 {
12     int i,j,t;
13     for(i=0;i<n;i++)    //
14         for(j=m;j>0;j--)    //当前背包容量
15             for(t=1;t<=j;t++)    //同一组内的所有物品,刚好每组m个
16                     dp[j]=max( dp[j] , dp[j-t]+a[i][t-1]    );
17 }
18 void main()
19 {
20     int n,m,i,j;
21     while(scanf("%d%d",&n,&m),n!=0)    //n门课,m天
22     {
23         for(i=0;i<n;i++)
24             for(j=0;j<m;j++)
25                 scanf("%d",&a[i][j]);
26         cal(n,m);
27         printf("%d\n",dp[m]);
28         memset(a,0,sizeof(int)*(num*n));    //清内存。如果怕麻烦,可以全清
29         memset(dp,0,sizeof(int)*(m+1));    //清内存    
30     }
31 }
1712

 

2、减少max函数  62MS

技术分享
 1 #include <iostream>
 2 #define num 101
 3 using namespace std;
 4 int a[num][num];
 5 int dp[num];
 6 void cal(int n,int m)
 7 {
 8     int i,j,t;
 9     for(i=0;i<n;i++)    //
10         for(j=m;j>0;j--)    //当前背包容量
11             for(t=1;t<=j;t++)    //同一组内的所有物品,刚好每组m个
12             {
13                 if(dp[j]<dp[j-t]+a[i][t-1])
14                     dp[j]=dp[j-t]+a[i][t-1];
15             }
16 }
17 void main()
18 {
19     int n,m,i,j;
20     while(scanf("%d%d",&n,&m),n!=0)    //n门课,m天
21     {
22         for(i=0;i<n;i++)
23             for(j=0;j<m;j++)
24                 scanf("%d",&a[i][j]);
25         cal(n,m);
26         printf("%d\n",dp[m]);
27         memset(a,0,sizeof(int)*(num*n));    //清内存。如果怕麻烦,可以全清
28         memset(dp,0,sizeof(int)*(m+1));    //清内存    
29     }
30 }
1712

 

3、用vector容器  62MS

技术分享
 1 #include <iostream>
 2 #include <vector>
 3 #define num 101
 4 using namespace std;
 5 vector<int> vect[num];
 6 int dp[num];
 7 void cal(int n,int m)
 8 {
 9     int i,j,t;
10     for(i=0;i<n;i++)    //
11         for(j=m;j>0;j--)    //当前背包容量
12             for(t=1;t<=j;t++)    //同一组内的所有物品,刚好每组m个
13             {
14                 if(dp[j]<dp[j-t]+vect[i][t-1])
15                     dp[j]=dp[j-t]+vect[i][t-1];
16             }
17 }
18 void main()
19 {
20     int n,m,i,j,temp;
21     while(scanf("%d%d",&n,&m),n!=0)    //n门课,m天
22     {
23         for(i=0;i<n;i++)
24             for(j=0;j<m;j++)
25             {
26                 scanf("%d",&temp);
27                 vect[i].push_back(temp);
28             }    
29         cal(n,m);
30         printf("%d\n",dp[m]);
31 
32         for(i=0;i<n;i++)    //清内存
33             vect[i].clear();
34         memset(dp,0,sizeof(int)*(m+1));    //清内存    
35     }
36 }
1712

 

4、别人的代码!124MS

技术分享
 1 #include<iostream>
 2 const int MAXN=110;
 3 using namespace std;
 4 int dp[MAXN];
 5 int map[MAXN][MAXN];
 6 
 7 int main(){
 8     int n,m;
 9     while(~scanf("%d%d",&n,&m)){
10         if(n==0&&m==0)break;
11         for(int i=1;i<=n;i++){
12             for(int j=1;j<=m;j++){
13                 scanf("%d",&map[i][j]);
14             }
15         }
16         memset(dp,0,sizeof(dp));
17         for(int i=1;i<=n;i++){
18             for(int j=m;j>=1;j--){
19                 for(int k=1;k<=m;k++){
20                     if(j-k>=0){
21                         dp[j]=max(dp[j],dp[j-k]+map[i][k]);
22                     }
23                 }
24             }
25         }
26         printf("%d\n",dp[m]);
27     }
28     return 0;
29 
30 }
1712

 

HDU 1712 ACboy needs your help AC男需要你的帮助 (AC代码)分组的背包问题

标签:

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

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