【并查集】【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;
}

posted @ 2024-10-26 00:27  peterzh6  阅读(1)  评论(0编辑  收藏  举报