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

 

题意:给出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代码

 

你可能感兴趣的:(love)