题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3449
题目大意:
fj打算去买一些东西,在那之前,他需要一些盒子去装他打算要买的不同的物品。每一个盒子有特定要装的东西(就是说如果他要买这些东西里的一个,他不得不先买一个盒子)。每一种物品都有自己的价值,现在FJ只有W元去购物,他打算用这些钱买价值最高的东西。
思路:
这是有依赖的背包,每件物品买之前必须买特定的盒子
所以先对每一个箱子进行01背包,保存可以凑出的所有的花费和该花费的最大价值,这是一组中的所有状态,且只能取一个或者不取,背包转化成分组背包,然后就可以做了。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 typedef pair<int, int> Pair ; 8 const int INF = 0x3f3f3f3f; 9 const int maxn = 1e5 + 10; 10 int T, n, m, cases; 11 struct node 12 { 13 int price; 14 int num; 15 int price_sum; 16 int cost[11], value[11]; 17 int dp[1005]; 18 }; 19 node a[100]; 20 int dp[maxn]; 21 int main() 22 { 23 while(cin >> n >> m) 24 { 25 memset(dp, 0, sizeof(dp)); 26 memset(a, 0, sizeof(a)); 27 for(int i = 0; i < n; i++) 28 { 29 scanf("%d%d", &a[i].price, &a[i].num); 30 a[i].price_sum = 0; 31 for(int j = 0; j < a[i].num; j++) 32 { 33 scanf("%d%d", &a[i].cost[j], &a[i].value[j]); 34 a[i].price_sum += a[i].cost[j]; 35 } 36 } 37 for(int i = 0; i < n; i++)//对,每个箱子预处理出所有可凑出的花费和该花费的最大价值 38 { 39 memset(a[i].dp, -1, sizeof(a[i].dp)); 40 a[i].dp[0] = 0; 41 for(int j = 0; j < a[i].num; j++) 42 { 43 for(int k = a[i].price_sum; k >= a[i].cost[j]; k--) 44 if(a[i].dp[k - a[i].cost[j]] >= 0)a[i].dp[k] = max(a[i].dp[k], a[i].dp[k - a[i].cost[j]] + a[i].value[j]); 45 }/* 46 for(int j = 0; j <= a[i].price_sum; j++) 47 cout<<a[i].dp[j]<<" "; 48 cout<<endl;*/ 49 } 50 for(int i = 0; i < n; i++)//枚举每一个的箱子 51 { 52 vector<Pair>d; 53 for(int j = 0; j <= a[i].price_sum; j++)//将该箱子的所有状态存下来 54 { 55 if(a[i].dp[j] > 0) 56 d.push_back(Pair(j + a[i].price, a[i].dp[j])); 57 } 58 for(int v = m; v >= 0; v--)//枚举花费 59 { 60 for(int j = 0; j < d.size(); j++)//枚举改组的状态 61 if(v >= d[j].first) 62 dp[v] = max(dp[v], dp[v - d[j].first] + d[j].second); 63 } 64 } 65 cout<<dp[m]<<endl; 66 } 67 return 0; 68 }
还有一种写法,在dp的时候把预处理和状态转化合并起来,时间复杂度降低了一点
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 typedef pair<int, int> Pair ; 8 const int INF = 0x3f3f3f3f; 9 const int maxn = 1e5 + 10; 10 int T, n, m, cases; 11 int a[105]; 12 int dp[55][100005]; 13 struct node 14 { 15 int v, w; 16 }; 17 vector<node>G[105]; 18 int main() 19 { 20 while(cin >> n >> m) 21 { 22 memset(dp, 0, sizeof(dp)); 23 for(int i = 1; i <= n; i++)G[i].clear(); 24 int tot, x, y; 25 for(int i = 1; i <= n; i++) 26 { 27 scanf("%d%d", &a[i], &tot); 28 for(int j = 0; j < tot; j++) 29 { 30 scanf("%d%d", &x, &y); 31 G[i].push_back(node{x, y}); 32 } 33 } 34 35 for(int i = 1; i <= n; i++)//枚举每种箱子 36 { 37 for(int j = 0; j < a[i]; j++)dp[i][j] = -1; 38 for(int j = a[i]; j <= m; j++)dp[i][j] = dp[i - 1][j - a[i]];//这里是确保先购买购物车 39 40 for(int j = 0; j < G[i].size(); j++)//在购物车内进行01背包 41 { 42 for(int k = m; k >= G[i][j].v; k--) 43 { 44 if(dp[i][k - G[i][j].v] != -1) 45 dp[i][k] = max(dp[i][k], dp[i][k - G[i][j].v] + G[i][j].w); 46 } 47 } 48 for(int j = 0; j <= m; j++)dp[i][j] = max(dp[i - 1][j], dp[i][j]);//和之前的值比较 49 } 50 cout<<dp[n][m]<<endl; 51 } 52 return 0; 53 }