现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。
输入格式:
输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。
输出格式:
输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。
输入样例:
6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3
输出样例:
12
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 1001;
int N, M, Father[MAXN],cnt=0, Cost=0;//Father为每棵树的根节点,cnt为已收入的边的条数,Cost为最终费用
struct Enode{//边节点
int v1, v2, w;
}E[3*MAXN];
bool cmp(Enode E1, Enode E2);//sort函数的比较方法,从小到大
int FindFather(int x);//找到一个节点所在树的根节点
int Kruskal();//若有最小生成树则返回最小花费,否则返回-1
int main()
{
scanf("%d%d",&N, &M);
for(int i=0;i<M;i++)
scanf("%d%d%d",&E[i].v1, &E[i].v2, &E[i].w);
printf("%d\n",Kruskal());
return 0;
}
int Kruskal(){
for(int i=1;i<=N;i++)//每个节点看成一棵树,根节点为其自身,注意是从1编号
Father[i] = i;
sort(E, E+M, cmp);//每个节点按权重排序,之后按此顺序检查边的两个顶点是否属于同一棵树并决定是否收入
for(int i=0;i<M;i++){
int Fa1 = FindFather(E[i].v1), Fa2 = FindFather(E[i].v2);//暂存一条边的两个顶点所在树的根节点
if(Fa1 != Fa2){//如果不属于同一棵树,即收入此边不会构成回路
Father[Fa2] = Fa1;//把v2根节点改为v1根节点,即合并两棵树,收入这条边
Cost += E[i].w;
cnt++;
}
if(cnt==N-1) break;//收入N-1条边即算法结束
}
return cnt==N-1 ? Cost : -1;//若无最小生成树则返回-1
}
bool cmp(Enode E1, Enode E2){
return E1.w < E2.w;
}
int FindFather(int x){
if(Father[x]==x) return x;
else return Father[x] = FindFather(Father[x]);
}