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代码

时间: 2024-08-09 13:00:35

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

HDU 3033 I love sneakers! 分组背包

我是个逗比...真心不是搞算法的料 不太中规中矩的分组背包,分组至少选一件商品.dp[i][j] 可以由当前dp[i-1][j-c] 和 dp[ i ][j-c]更新得到. #include <iostream> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <cmath

hdu 3033 I love sneakers!

题目: 链接:点击打开链接 题意: xx喜欢收集鞋子,n,m,k分别表示鞋子的总数,xx的钱和鞋子的品牌数目.然后给出每个鞋子的信息有:a,是那种品牌,b,鞋子的标价,c,收藏鞋子得到的价值.对于一个收藏家来说,每种品牌的鞋子只收集一种,求出xx能够得到的最大的收藏价值. 算法: 分组背包问题. 思路: m总的钱数是背包容量,k品牌数是组数.用数组结构体保存每种鞋子的信息,d[i][j].w表示第i种品牌的鞋子中的第j个鞋子的标价,d[i][j].v表示第i种品牌的鞋子中的第j个鞋子价值.状态转

hdu 3033 I love sneakers!(分组背包,每组至少取一件)

http://acm.hdu.edu.cn/showproblem.php?pid=3033 大致题意:某人要买鞋子,有k种鞋,要求每种鞋至少买一双,给出每双鞋子的花费和价值,问m元钱可以买到的鞋子的最大价值是多少. 思路:分组背包问题.与传统的分组背包不同:每组物品至少取一件:且每组中物品任意取. 想一想传统的分组背包,每组至多选一件: for 所有的组k     for v=V..0         for 所有的i属于组k             f[v]=max{f[v],f[v-c[i

HDU 3033 I love sneakers! (01背包+反分组背包)

题意:给你 n,m,k,表示有k种鞋子共n双,你有m的容量: 每双鞋子有容量p和价值v:问是否买全k种鞋子,若能在容量为m的情况下最多能买到鞋子的价值为多少: 每双鞋子只能买一次(01背包),每种鞋子至少买一种(分组背包:每组只能有一个)与传统分组背包的限制相反. 注意初始化!!! #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map&g

HDU 3033 I love sneakers! (DP 01背包+完全背包)

Problem Description After months of hard working, Iserlohn finally wins awesome amount of scholarship. As a great zealot of sneakers, he decides to spend all his money on them in a sneaker store. There are several brands of sneakers that Iserlohn wan

HDU 3591 The trouble of Xiaoqian(多重背包+01背包)

HDU 3591 The trouble of Xiaoqian(多重背包+01背包) http://acm.hdu.edu.cn/showproblem.php?pid=3591 题意: 有一个具有n种货币的货币系统, 每种货币的面值为val[i]. 现在小杰手上拿着num[1],num[2],-num[n]个第1种,第2种-第n种货币去买价值为T(T<=20000)的商品, 他给售货员总价值>=T的货币,然后售货员(可能,如果小杰给的钱>T, 那肯定找钱)找钱给他. 售货员每次总是用

hdu 3033 I love sneakers!【详剖 DP 之 分组背包 】

I love sneakers! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4538    Accepted Submission(s): 1866 Problem Description After months of hard working, Iserlohn finally wins awesome amount of s

[HDU 3033] I love sneakers! (动态规划分组背包)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3033 题意:给你K种品牌,每种品牌有不同种鞋,现在每种品牌至少挑一款鞋,问获得的最大价值,如果不能每种品牌都挑到则输出Impossible 自己太弱了!!!!!这个题都想不出来!!!!!还要看题解!!!!!! 设计状态dp[i][j]代表从前i种品牌里花了不超过j元钱. 那么状态转移可以这样: 1.我只买第i种品牌的第k个. 2.我在第i种品牌里不光买第k个. 变成状态转移方程就是: 1. dp[i

hdu 2126 Buy the souvenirs 【输出方案数】【01背包】(经典)

题目链接:https://vjudge.net/contest/103424#problem/K 题目大意: 给n个物品,和m块钱,输出能够购买最多物品的个数和购买这么多物品的方案数. #include <cstring> #include <iostream> #include <algorithm> #define clr(a) (memset(a,0,sizeof(a))) using namespace std; int dp[510][50], a[50];