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;
}