题意:给你若干个集合,每个集合内的物品要么选任意一个,要么所有都选,求最后在背包能容纳的范围下最大的价值。

  分析:对于每个并查集,从上到下滚动维护即可,其实就是一个01背包= =。

  代码如下:

 1 #include <stdio.h>
 2 #include <algorithm>
 3 #include <string.h>
 4 #include <vector>
 5 using namespace std;
 6 const int N = 1000 + 5;
 7 
 8 int w[N],b[N];
 9 int n,m,W;
10 int root[N];
11 vector<int> v[N];
12 int allw[N],allb[N];
13 int dp[N];
14 int find(int x) {return x == root[x] ? x : root[x] = find(root[x]);}
15 
16 int main()
17 {
18     scanf("%d%d%d",&n,&m,&W);
19     for(int i=1;i<=n;i++) root[i] = i;
20     for(int i=1;i<=n;i++) scanf("%d",w+i);
21     for(int i=1;i<=n;i++) scanf("%d",b+i);
22     for(int i=1;i<=m;i++)
23     {
24         int x,y;scanf("%d%d",&x,&y);
25         int rx = find(x), ry = find(y);
26         if(rx != ry) root[rx] = ry;
27     }
28     for(int i=1;i<=n;i++)
29     {
30         int t = find(i);
31         v[t].push_back(i);
32         allw[t] += w[i];
33         allb[t] += b[i];
34     }
35     for(int i=1;i<=n;i++)
36     {
37         if(v[i].size() == 0) continue;
38         for(int j=W;j>=0;j--)
39         {
40             for(int k=0;k<v[i].size();k++)
41             {
42                 if(j-w[v[i][k]] >= 0) dp[j] = max(dp[j], dp[j-w[v[i][k]]] + b[v[i][k]]);
43             }
44             if(j-allw[i] >= 0) dp[j] = max(dp[j], dp[j-allw[i]] + allb[i]);
45         }
46     }
47     printf("%d\n",dp[W]);
48     return 0;
49 }