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 }