当前位置: 代码迷 >> 综合 >> poj3723 Conscription(最小生成树)
  详细解决方案

poj3723 Conscription(最小生成树)

热度:71   发布时间:2023-12-11 20:49:07.0

题意

要征募n个男兵,m个女兵,每招一个人要10000块钱,现在有一些男兵和女兵有某种关系,导致同时招募他们可以节省一定的钱,给出男女兵的关系,求招募最少要花多少钱。

思路

其实很简单,选的人里面含有的关系能省的钱要最大,把男女关系连起来形成一个图,就是求这个图的最大生成树。我们猜测最大生成树算法可以类比最小生成树的贪心算法(确实是对的)。不过我们这里可以换个思路,把权值全改成负数,那这样求最小生成树得到的也是我们要的值。

代码

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;const int kMaxn = 50000 + 10;struct Edge {int u,v;int d;
} g[kMaxn];int f[kMaxn];
int n,m,r;int Init() {for(int i = 0; i <= n + m; i++)f[i] = i;
}int Findf(int x) {if(f[x] != x)f[x] = Findf(f[x]);return f[x];
}void Union(int a, int b) {int fa = Findf(a);int fb = Findf(b);f[fb] = fa;
}bool cmp(Edge a, Edge b) {return a.d < b.d;
}int Kruskal() {Init();int sum = 0;sort(g + 1, g + 1 + r, cmp);for(int i = 1; i <= r; i++) {int u = g[i].u;int v = g[i].v;if(Findf(u) != Findf(v)) {sum += g[i].d;Union(u, v);}}return sum;
}int main() {int T;scanf("%d", &T);while(T--) {scanf("%d %d %d", &n, &m, &r);memset(g, 0, sizeof(g));for(int i = 1; i <= r; i++) {int u,v,d;scanf("%d %d %d", &u, &v, &d);g[i].u = u;g[i].v = v + n;g[i].d = -d;}printf("%d\n", (n + m) * 10000 + Kruskal());}return 0;
}