问题 B: PK吹泡泡
时间限制: 1 Sec 内存限制: 128 MB
[提交][状态][讨论版]
题目描述
经历了一天的训练之后, PK准备放松一下,在草坪上吹起了泡泡。经历了 PK 的一顿操作之后,天空中出现了 n 个泡
泡,每个泡泡都有个编号。 给出了m个关系,每个关系以u v w 的形式给出,表示编号为u的泡泡可以和编号为v的
泡泡连在一起,且花费的代价为 w。
这时, PK 想到了一个问题:如何以最小的代价把这 n 个泡泡中的一些泡泡连在一起,使得天空中出现 k 个泡泡联通
块?可是PK沉浸在了泡泡的海洋无法自拔,不想思考这个问题,他希望你来替他回答。
输入
第一行三个整数 n,m,k (1 ≤ k < n ≤ 1000, 1 ≤ m ≤ 500000 )。表示泡泡的个数,PK 给出的关系数以及最终要
形成的泡泡联通块数。
接下来的m行 ,每行三个数 u,v,w(1 ≤ u, v ≤ n, 0 < w ≤ 1000000 ) ,表示你可以把泡泡 u 和泡泡 v 连在一起,需要
花费的代价为 w。
输出
输出一个整数,表示把这n个泡泡中的一些泡泡连在一起使得天空中出现k个泡泡联通块的最小代价
样例输入
4 4 2
1 2 1
2 3 4
3 4 2
1 4 5
样例输出
3
提示
数据保证有解
数据保证图联通
/*
认真读题,再画出样例,其实这题就是一个最小生成树,用Kruscal,开始时,有多少个点就要多少个联通块,每次选定一条边,联通块个数就会少一个。
所以用Kruscal选边,直到连通块只剩K个即可返回最小代价。
*/
Ac_code:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL maxn = 5e5+2;
struct Edge
{
LL s,e;
LL val;
bool operator<(const Edge x)const
{
return val<x.val;
}
}a[maxn];
LL pre[maxn];
LL myFind(LL x)
{
return pre[x]==x?x:pre[x]=myFind(pre[x]);
}
LL kruscal(LL n,LL m,LL k)
{
for(LL i = 1; i <= n; i++)
{
pre[i] = i;
}
sort(a,a+m);
LL sum = 0,cnt = 0;
for(LL i = 0; i < m; i++)
{
LL fx = myFind(a[i].s);
LL fy = myFind(a[i].e);
if(fx != fy)
{
pre[fx]=pre[fy];
sum += a[i].val;
cnt++;
if(n-cnt == k)
{
return sum;
}
}
}
}
int main()
{
LL n,m,k;
scanf("%lld%lld%lld",&n,&m,&k);
for(LL i = 0; i < m; i++)
{
scanf("%lld%lld%lld",&a[i].s,&a[i].e,&a[i].val);
}
printf("%lld\n",kruscal(n,m,k));
return 0;
}