【并查集】【01背包】经商
https://ac.nowcoder.com/acm/contest/22904/1022
并查集:通过并查集找到所有与1连通的节点。
动态规划:使用01背包来处理这些与1连通的节点,在精力范围内求得最大利益。
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
using namespace std;
// 并查集查找函数,带路径压缩
int find(vector<int>& parent, int x) {
if (parent[x] != x) {
parent[x] = find(parent, parent[x]);
}
return parent[x];
}
// 并查集合并函数
void unite(vector<int>& parent, int x, int y) {
int rootX = find(parent, x);
int rootY = find(parent, y);
if (rootX != rootY) {
parent[rootY] = rootX;
}
}
int main() {
int t;
cin >> t;
while (t--) {
int N, M, C;
cin >> N >> M >> C;
vector<int> parent(N + 1);
for (int i = 1; i <= N; ++i) {
parent[i] = i;
}
vector<int> cost(N + 1, 0); // 花费的精力
vector<int> profit(N + 1, 0); // 获得的利益值
// 读取每个人的交际花费和利益
for (int i = 2; i <= N; ++i) {
cin >> cost[i] >> profit[i];
}
// 读取关系网并构建并查集
for (int i = 0; i < M; ++i) {
int x, y;
cin >> x >> y;
unite(parent, x, y);
}
// 找出与小d(编号1)连通的节点
int root1 = find(parent, 1);
vector<pair<int, int>> items; // 存储与小d连通的人的<花费, 利益>对
for (int i = 2; i <= N; ++i) {
if (find(parent, i) == root1) {
items.emplace_back(cost[i], profit[i]);
}
}
// 01背包求解最大利益
vector<int> dp(C + 1, 0);
for (auto [w, v] : items) {
for (int j = C; j >= w; --j) {
dp[j] = max(dp[j], dp[j - w] + v);
}
}
// 输出最大利益值
cout << dp[C] << endl;
}
return 0;
}