题目描述: 有n个人(1<=n<=1000)。每个人有一个重量wi(1<=wi<=1000)和一个魅力值bi(1<=bi<=10^6)。 n个人之间有m(1<=m<=min(n*(n-1)/2, 10^5))个关系。第i个关系由两个数字xi和yi组成,表示第xi个人和第yi个人是朋友,朋友关系是双向的。 已知若a和b是朋友,b和c是朋友,则a和c是朋友。 现在Mehrdad要邀请一些人来到派对,使这些人的重量总和不超过wi(1<=wi<=1000),且魅力值总和尽量大。同一个朋友圈里的人,只能邀请其中的一个人,或者全部人,或者一个人也不邀请。

输入格式: 第一行,三个整数n,m,w 第二行,n个整数w1,w2,...,wn 第三行,n个整数b1,b2,...,bn 接下来m行,每行表示一个关系,第i行有两个整数xi和yi。每一组朋友关系都是不同的。

输出格式: 一行,表示最大的魅力值总和。

题解:首先使用并查集将同一个集合的人合并到一个根上,然后多生成一个suma, sumb,对该根上的每一个元素我们使用01背包求出最大值

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2000 + 5;
int a[maxn], b[maxn];
int sum1[maxn], sum2[maxn];
int fa[maxn];
vector<int> arr[maxn];
int dp[maxn][maxn];
int find(int x) {
    return x == fa[x] ? x : fa[x] = find(fa[x]);
}
int main() {
    int n, m, w, u, v;
    cin >> n >> m >> w;
    for (int i = 1; i <= n; i++) fa[i] = i;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++) cin >> b[i];
    for (int i = 1; i <= m; i++) {
        cin >> u >> v;
        int fu = find(u);
        int fv = find(v);
        if (fu != fv) {
            fa[fu] = fv;
        }
    }

    for (int i = 1; i <= n; i++) find(i);
    for (int i = 1; i <= n; i++) {
        int u = find(i); 
        arr[u].push_back(i);
        sum1[u] += a[i];
        sum2[u] += b[i];
    }
    for (int i = 1; i <= n; i++) {
        for (int k = 0; k <= w; k++) {
            dp[i][k] = dp[i - 1][k];
        }
        for (int j = 0; j < arr[i].size(); j++) {
            int t1 = a[arr[i][j]];
            int t2 = b[arr[i][j]];
            for (int k = t1; k <= w; k++) {
                dp[i][k] = max(dp[i][k], dp[i - 1][k - t1] + t2);
            }
        }
        for (int k = sum1[i]; k <= w; k++) {
            dp[i][k] = max(dp[i][k], dp[i - 1][k - sum1[i]] + sum2[i]);
        }
    }
    printf("%d\n", dp[n][w]);
    return 0;
}