hdu-3449 Consumer---有依赖性质的背包

题目链接:

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 }

 

转载于:https://www.cnblogs.com/fzl194/p/8833098.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值