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

HDU 3033 I love sneakers! 我爱运动鞋 (分组背包,01背包,严重变形)

时间:2015-05-22 13:11:02      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:

 

题意:给出k家店,每家店内有各种价格的鞋子(同样的鞋子只能买一双),每双鞋子有价值,要求每家店至少买一双。给出m钱,求获得的最大价值。

思路:分组背包严重变形了,变成了相反的,每组物品至少挑1件(分组背包是至多挑1件)。虽然是分组背包的变形,但是用到的却是01背包的思路。要求每家店至少买1双,那么可以只买一双双,也可以买多双。难点在这。需要维护两行dp状态值即可。第一行是前面组的物品的最佳状态,第二行是第i件物品之前的最佳状态(已经装进同组物品)。

  对于i组第t件物品,(1)要么从i组之前的状态转移而来(即目前为止,i组只买第t件),(2)要么从已经买了i组第t件之前(包括1~i-1组)的状态转移而来。但是这样并不能保证第i组一定会有鞋子被选中,有可能第t件不划算,不装,同时,相比同组的其他件也不划算,不装。为解决此问题,先预装一件最便宜的上去,即上面提到的第二行更新为“必装第i组最便宜的鞋”,这样保证了至少每组至少一件。如果官方答案中应该第i组只可能装一件,且不是最便宜的那件,那么用第(1)种转移方法肯定可以覆盖掉前面预装的;如果应该第i组要装多件,那么从第(2)种转移方法就能从同组中多件一块考虑。

  至关重要的是,对于每种容量j,如果买不起所有店最便宜的鞋子,那么作废,因为不符合要求。比如说,考虑第2组第1件时,dp[1][0~第1组中最便宜鞋价-1]的状态作废,因为0~第1组中最便宜鞋价-1这段状态已经连第1组中最便宜的鞋都买不起,是不符合要求的,即使答案用到这些状态,那也是不符合要求的,所以提前作废,只需要在考虑容量时注意下限就行了。

  巨坑!每家店可是不一定有鞋子的,比如给出k家店,k-1件鞋子,这是可能的。一旦出现这种情况,立马输出“不可能”。

技术分享
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int n, m, k, w, dp[15][11000];
 4 struct node
 5 {
 6     int p,v;
 7 }r;
 8 vector< vector<node> > vect;
 9 inline int cmp(node a,node b){return a.p< b.p? 1: 0;}
10 int cal()
11 {
12     memset(dp,0,sizeof(dp));
13     int up=0;
14     for(int i=1; i<=k; i++)             //每组
15     {
16         r=vect[i][0];
17         for(int j=m; j>=up+r.p; j--)    //先装进去每组中最便宜的一个,有更好的再更新
18             dp[i][j]=dp[i-1][j-r.p]+r.v;
19 
20         for(int t=1; t<vect[i].size(); t++)//同组每种鞋
21         {
22             r=vect[i][t];
23             for(int j=m; j>=up+r.p; j--)  //每种容量。注意下限是前面所有店的最便宜鞋价的总和。最差也能买上前面所有店的最便宜的鞋子,其他都是无效的状态。
24             {
25                 dp[i][j]=max(dp[i][j], dp[i-1][j-r.p]+r.v );    //单独放。
26                 dp[i][j]=max(dp[i][j], dp[i][j-r.p]  +r.v );    //配合同组放。
27             }
28         }
29         up+=vect[i][0].p;   //更新下限
30     }
31     if(dp[k][m]>0)    return 1;
32     else    return 0;
33 }
34 void init()
35 {
36     vect.clear();
37     vector<node> tmp;
38     for(int i=0; i<=k; i++) vect.push_back(tmp);
39 }
40 
41 int main()
42 {
43     freopen("input.txt", "r", stdin);
44     while(cin>>n>>m>>k)
45     {
46         init();
47         for(int i=0; i<n; i++)
48         {
49             scanf("%d%d%d", &w, &r.p, &r.v);
50             vect[w].push_back(r);//分组保存
51         }
52         int big=0;
53         for(int i=1; i<=k; i++)
54         {
55             sort(vect[i].begin(), vect[i].end(), cmp);    //排个序,最低价的排在前面
56             if(!vect[i].empty())    big+=vect[i][0].p;  //坑在这,有的店完全没有鞋子!
57             else    big=0x7fffffff;//既然没有鞋子,置为无穷大,表示买不起。
58         }
59         if(big>m){printf("Impossible\n");continue;}   //每家店最便宜的鞋子都买不起
60         if(cal())    printf("%d\n",dp[k][m]);
61         else    printf("Impossible\n");
62     }
63     return 0;
64 }
AC代码

 

HDU 3033 I love sneakers! 我爱运动鞋 (分组背包,01背包,严重变形)

标签:

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

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