题目描述: 有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; }