POJ 3723 Conscription(并查集+最小生成树)

来源:互联网 发布:莫一兮 知乎 编辑:程序博客网 时间:2024/06/01 18:03

题目链接:https://cn.vjudge.net/problem/POJ-3723

大意:需要招募女兵N人,男兵M人。每招募一个人需要花费10000美元。但是如果已经招募的人中有一些关系亲密的人,那么可以少花一些钱(10000-亲密值)。给出若干男女之间的亲密关系,求招募所有人的最小费用。(招募每个人时只能用一条关系)

思路:将人看做点(N+M个点),关系看作边,边权为亲密值的相反数。然后对整个图求最小生成树,答案就是10000*(N+M)再加上最小生成树的值。


#include<iostream>#include<cstring>#include<algorithm>#include<cstdio>#include<vector>#include<queue>#include<cmath>using namespace std;typedef long long ll;const int maxn = 50000 + 5;int fa[maxn];struct Edge {   int from, to, cost;   bool operator < (const Edge& rhs) const {      return cost < rhs.cost;   }   Edge(int from, int to, int cost):from(from),to(to),cost(cost){}};vector<Edge> edges;int find(int x) {   if(fa[x] == -1) return x;   return fa[x] = find(fa[x]);}int kruskal(int n){    sort(edges.begin(), edges.end());    int num = 0, ans = 0;    for(int i = 0; i < edges.size(); i++) {        int x = find(edges[i].from), y = find(edges[i].to);        if(x != y) {            fa[x] = y;            num++;            ans += edges[i].cost;            if(num == n-1) break;        }    }    return ans;}int main(){    int T;    scanf("%d", &T);    while(T--) {        int n, m, r;        scanf("%d%d%d", &n, &m, &r);        memset(fa, -1, sizeof fa);        edges.clear();        while(r--) {            int x, y, d;            scanf("%d%d%d", &x, &y, &d);            x++, y++;            edges.push_back(Edge(x, y+n,-d));        }        printf("%d\n", (n+m)*10000+kruskal(m+n));    }}


0 0
原创粉丝点击