题意:
有n<=100双鞋子,分别属于一个牌子,共k<=10个牌子。现有m<=10000钱,问每个牌子至少挑1双,能获得的最大价值是多少?
思路:
分组背包的变形,变成了相反的,每组物品至少挑1件(分组背包问题是至多挑1件)。
由于每个牌子至少买1双,那么可以先装一件最便宜的进去,如果有好的再更新(注意每次的容量下限)。而且同一双鞋子不能多次购买,这里要用01背包。对于当前容量cap,可能只装了某一牌子的一双鞋子(不一定最便宜),也可能装了多双,也可能只装了那双硬塞进去的最便宜的。
注意点:有的店可是不一定有鞋子的;可能某个牌子连一双都买不起;可能买不全所有牌子。
重写了次:
1 //#include <bits/stdc++.h> 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <set> 7 #include <deque> 8 #include <map> 9 #include <algorithm> 10 #include <vector> 11 #include <iostream> 12 #define pii pair<int,int> 13 #define back que[rear-1] 14 #define INF 0x3f3f3f3f 15 #define LL long long 16 #define ULL unsigned long long 17 using namespace std; 18 const double PI = acos(-1.0); 19 const int N=10010; 20 int dp[11][N]; 21 struct node 22 { 23 int p,v; 24 }r; 25 vector<node> vect[N]; 26 inline int cmp(node a,node b){return a.p<b.p;} 27 bool cal(int n,int m,int k) 28 { 29 for(int i=1; i<=n; i++) //排序方便处理 30 sort(vect[i].begin(),vect[i].end(),cmp); 31 int sum=0; //最便宜的鞋子价钱之和 32 for(int i=1; i<=k; i++) //枚举组 33 { 34 if(vect[i].empty()) return false; //无鞋 35 36 node a=vect[i][0]; 37 for(int j=m; j-a.p>=sum; j--) //先装进去一个最便宜的 38 dp[i][j]=dp[i-1][j-a.p]+a.v; 39 40 for(int t=1; t<vect[i].size(); t++) //考虑此组其他鞋 41 { 42 a=vect[i][t]; 43 for(int j=m; j-a.p>=sum; j--) 44 { 45 dp[i][j]=max(dp[i][j], dp[i-1][j-a.p]+a.v ); //注意点 46 dp[i][j]=max(dp[i][j], dp[i][j-a.p]+a.v ); 47 } 48 } 49 sum+=vect[i][0].p; 50 if(sum>m) return false; //买不起 51 } 52 return true; 53 } 54 55 int main() 56 { 57 //freopen("input.txt", "r", stdin); 58 int w, n, m, k; 59 while(cin>>n>>m>>k) //n双鞋子,m钱,k个牌子 60 { 61 memset(dp,0,sizeof(dp)); 62 for(int i=0; i<=k; i++) vect[i].clear(); 63 for(int i=1; i<=n; i++) 64 { 65 scanf("%d%d%d", &w, &r.p, &r.v); 66 vect[w].push_back(r); //分组保存 67 } 68 if(cal(n,m,k)) printf("%d ",dp[k][m]); 69 else printf("Impossible "); 70 } 71 return 0; 72 }
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 ");continue;} //每家店最便宜的鞋子都买不起 60 if(cal()) printf("%d ",dp[k][m]); 61 else printf("Impossible "); 62 } 63 return 0; 64 }