最小生成树 Kruskal(克鲁斯卡尔)算法

Description

省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。 

 

Input

测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N 
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。 

 

Output

对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。 

 

Sample Input

 

3 3 1 2 1 1 3 2 2 3 4 1 3 2 3 2 0 100

 

Sample Output

 

3 ?

 

AC代码:

#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; const int N=10000+20; int uset[N]; int ran[N]; struct Node {     int x,y,price; } s[N]; bool cmp(Node a,Node b) //按权值从小到大排序 {     return a.price<b.price; } void makeset(int n) //建立并查集 {     for(int i=1; i<=n; i++)         uset[i]=i,ran[i]=0; } int find(int x) {     while(uset[x]!=x)         x=uset[x];     return x; } void unionset(int x,int y) //按秩合并 {     int a=find(x),b=find(y);     if(a==b)         return ;     if(ran[a]>ran[b])         uset[b]=a;     else     {         if(ran[a]==ran[b])             ran[b]++;         uset[a]=b;     } } int kruskal(int n,int m) //克鲁斯卡尔算法 {     int res=0,i;     sort(s+1,s+n+1,cmp);     for(i=1; i<=n; i++)     {         if(find(s[i].x)!=find(s[i].y))         {             unionset(s[i].x,s[i].y);             res +=s[i].price;         }     }     return res; } int main() {     int n,m;     int i,j;     int ans=0;     while(scanf("%d%d",&n,&m)!=EOF&&n)     {         ans=0;         makeset(m);         for(i=1; i<=n; i++)             scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].price);         ans=kruskal(n,m);         for(i=2; i<=m; i++) //判断所有城市有没有连到一起 及测试连通性         {             if(find(1)!=find(i))             {                 ans=-1;                 break;             }         }         if(ans==-1)             printf("?\n");         else             printf("%d\n",ans);     }     return 0; }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值