CSU 1326:The contest(并查集+分组背包)

http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1326

题意:……

思路:并查集建图处理出边,然后分组背包。

之前不会分组背包,比赛的时候也推不出来,不知道互斥的情况怎么搞。原来就和01背包差不多,只不过是把每个组当作一个物品,然后枚举容量的时候,加上内层枚举组内的物品。注意第三层枚举组内物品要写在容量的内层,才能满足组内最多选一个的互斥条件。这里分析的挺好的:http://www.cppblog.com/Onway/archive/2010/08/09/122695.html

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <string>
 6 #include <cmath>
 7 #include <queue>
 8 #include <vector>
 9 #include <map>
10 #include <set>
11 #include <stack>
12 using namespace std;
13 #define INF 0x3f3f3f3f
14 #define N 1010
15 typedef long long LL;
16 vector<int> G[N];
17 int fa[N], w[N], p[N];
18 int dp[N];
19 int Find(int x) { if(x == fa[x]) return x; return fa[x] = Find(fa[x]); }
20 void Merge(int x, int y) { x = Find(x), y = Find(y); if(x != y) fa[x] = y; }
21 
22 int main() {
23     int n, tol, k;
24     while(~scanf("%d%d%d", &n, &tol, &k)) {
25         for(int i = 1; i <= n; i++) fa[i] = i;
26         for(int i = 1; i <= n; i++) G[i].clear();
27         memset(dp, 0, sizeof(dp));
28         for(int i = 1; i <= n; i++) scanf("%d%d", &p[i], &w[i]);
29         for(int i = 0; i < k; i++) {
30             int u, v; scanf("%d%d", &u, &v);
31             Merge(u, v);
32         }
33         for(int i = 1; i <= n; i++) {
34             int u = Find(i);
35             G[u].push_back(i);
36         }
37         for(int u = 1; u <= n; u++) { // 枚举物品
38             if(fa[u] == u) { // 相同集合的物品
39                 for(int i = tol; i >= 0; i--) { // 相当于把这组物品当做一个物品来作DP
40                     for(int j = 0; j < G[u].size(); j++) {
41                         int now = G[u][j];
42                         if(i - w[now] >= 0)
43                             dp[i] = max(dp[i], dp[i-w[now]] + p[now]);
44                     }
45                 }
46             }
47         }
48         printf("%d\n", dp[tol]);
49     }
50     return 0;
51 }

 

转载于:https://www.cnblogs.com/fightfordream/p/6298639.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值