题意: 给出上限体重W
然后还给出每个人的体重wi 和 魅力值 bi
互为伙伴的对(xi, yi) 可以凑成group
思路:
并查集找出所有的group
暴力背包
对于每一个group 要选出这一组内选一个人时的最优结果, 如果所有人的体重和小于等于W,还得考虑选所有人的情况
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <map>
#include <queue>
#include <vector>
using namespace std;
int w[2000];
int b[2000];
int fa[2000];
int dp[2000][2000];
bool vis[2000];
vector<int>group[2000];
int cnt = 0, ans = 0;
void init(int n) { for (int i = 0; i <= n; ++i) fa[i] = i, vis[i] = false; }
int find(int x) { return fa[x] == x ? fa[x] : fa[x] = find(fa[x]); }
void unite(int x, int y) { int fx = find(x), fy = find(y); if (fx == fy)return; if (fx > fy) fa[fx] = fy; else fa[fy] = fx; }
int main() {
ios::sync_with_stdio(false);
int n, m, W; cin >> n >> m >> W; init(n);
for (int i = 1; i <= n; ++i) cin >> w[i];
for (int i = 1; i <= n; ++i) {
cin >> b[i];
}
while (m--) {
int u, v; cin >> u >> v;
unite(u, v);
}
for (int i = 1; i <= n; ++i) {
if (vis[i]) continue;
vis[i] = true;
group[++cnt].push_back(i);
for (int j = i + 1; j <= n; ++j) {
if (find(i) == find(j)) {
vis[j] = true;
group[cnt].push_back(j);
}
}
}
memset(dp, 0, sizeof dp);
for (int i = 1; i <= cnt; ++i) {
int sz = group[i].size();
int maxx = 0; int sum = 0; int beauty = 0;
for (int j = 0; j <= W; ++j) dp[i][j] = dp[i-1][j];
for (int j = 0; j < sz; ++j) {
sum += w[group[i][j]];
beauty += b[group[i][j]];
if (w[group[i][j]] <= W) {
for (int k = W; k >= w[group[i][j]]; --k) {
dp[i][k] = max(dp[i][k], dp[i - 1][k - w[group[i][j]]] + b[group[i][j]]);
}
}
}
if (sum <= W) {
for (int k = W; k >= sum; --k) {
dp[i][k] = max(dp[i][k], dp[i - 1][k - sum] + beauty);
}
}
}
for (int j = 1; j <= cnt; ++j)
for (int i = 0; i <= W; ++i)
ans = max(ans, dp[j][i]);
cout << ans << endl;
return 0;
}
/*
10 5 100
70 67 8 64 28 82 18 61 82 7
596434 595982 237932 275698 361351 850374 936914 877996 789231 331012
1 7
2 4
3 6
5 7
1 5
*/