1.题目描述:点击打开链接
2.解题思路:本题考察最小生成树,利用Kruskal算法解决。我们来设想一下这样一个无向图:如果在征募某个人a时,利用了a和b之间的关系,那么就有一条a到b的边。假设这个图中存在圈,那么无论以什么顺序征募这个圈上的所有人,都会产生矛盾。因为其中的关系必须单向利用。比如B和A最亲近,那么有一条边A->B,而C又和B最亲近,那么有B->C,可能实际上A和C也是最亲近的,但由于A是第一个被招进来的,因此不可能利用到A和C的关系,即不能有圈存在!因此最后这些点连接出来的是一棵树或者森林。这可以用Kruskal算法解决。
那么如何求得最小花费呢?通过谈心的思想我们会发现,我们希望先利用上亲密度最高的,这样会更省钱。那么只需要把权值取反后即可用Kruskal算法解决了,因为Kruskal算法总是优先选取权值最小的边!最后求出最小权值后加上10000*(n+m)即为最终的答案。
3.代码:
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm> #include<string> #include<sstream> #include<set> #include<vector> #include<stack> #include<map> #include<queue> #include<deque> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<functional> using namespace std; #define N 50000+10 int n, m, r; struct Edge { int x, y, d; bool operator <(const Edge&r)const { return d < r.d; } void read() { scanf("%d%d%d", &x, &y, &d); y += n, d = -d; } }c[N]; int p[N]; int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); } int Kruskal() { for (int i = 0; i < N; i++) p[i] = i; sort(c, c + r); int res = 0; for (int i = 0; i < r; i++) { int x = find(c[i].x), y = find(c[i].y); if (x != y) { res += c[i].d; p[x] = y; } } return res; } int main() { //freopen("t.txt", "r", stdin); int t; scanf("%d", &t); while (t--) { scanf("%d%d%d", &n, &m, &r); memset(c, 0, sizeof(c)); for (int i = 0; i < r; i++) c[i].read(); printf("%d\n", 10000 * (n + m) + Kruskal()); } return 0; }
原文地址:http://blog.csdn.net/u014800748/article/details/44924673