题目描述
题目出处:点这里
输入格式
输出格式
样例
输入
3 1 2
1 2 1
输出
1
提示
样例规模
分析与思路
本题要求的值是当云朵有K块时,所花费的最小代价,最小代价很容易让我们想到最小生成树,但是我们如何判断有没有将云朵分成K块呢,要知道最小生成树可只有一棵啊
这时候就需要Keruskal算法的帮助了,Keruskal 算法使用了并查集来实现寻找最小生成树的功能,所以我们只需要在运行Keruskal 算法的时候,统计当前剩下的集合个数,就可以在集合个数达到K的时候输出正确答案了
代码实现
#include<bits/stdc++.h>
using namespace std;
struct Node{
int n1,n2,w;
Node(){}
Node(int i,int d,int l){
n1=i;n2=d;w=l;
}
friend bool operator < (Node a,Node b){
return a.w<b.w;
}
};
Node edges[10005];
int n,m,k;
int u,v,c;
int mf[10005];
bool check=false;
int find(int v){
if(v==mf[v]){
return v;
}else{
return find(mf[v]);
}
}
vector<int> Keruskal(){
vector<int>result;
sort(edges+1,edges+1+m);
for(int i=1;i<=n;i++)mf[i]=i;
int jhsum=n;//用于记录集合数量
for(int i=1;i<=m;i++){
int t1=find(edges[i].n1);
int t2=find(edges[i].n2);
if(t1==t2)continue;
mf[t2]=t1;jhsum--;
result.push_back(i);
if(jhsum==k){//如果集合数量达到K
check=true;//记录下来:可以分成K朵
break;//就可以退出循环
}
}
return result;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&c);
edges[i].n1=v;
edges[i].n2=u;
edges[i].w=c;
}
if(n==k){//云朵数量和要求数量K相等
printf("0");
return 0;
}
if(n<k){//云朵数量比要求数量K小
printf("No Answer");
return 0;
}
vector<int>Nodes=Keruskal();
if(check){//判断能否分成K块
long long sum=0;
for(int ab : Nodes){
sum+=edges[ab].w;
}
printf("%d",sum);
}else{
printf("No Answer");
}
return 0;
}