1. 程式人生 > >Kruskal演算法-HDU1863暢通工程

Kruskal演算法-HDU1863暢通工程

連結

[http://acm.hdu.edu.cn/showproblem.php?pid=1863]

題意

Problem 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
?

分析

Kruskal求最小生成樹

程式碼

#include<iostream>
#include<algorithm>
using namespace std;
int par[1000];//祖先 
int r[1000];//祖先的等級 
typedef struct{//a到b以及距離 
    int a,b,price;
}node;
node a[1000];
bool cmp(node &x,node &y){
    return x.price<y.price;
}
void init(int n){
   for(int i=1;i<=n;i++){
     par[i]=i; r[i]=1;//剛開始祖先是自己,祖先等級是1 
   }    
}
int find(int x){
if(x==par[x]) return par[x];//如果祖先是自己返回 
   else{
    par[x]=find(par[x]); return par[x];//祖先是它祖先的祖先 
   }
}
void merge(int u,int v){//合併二者的祖先 
    int f1=find(u);
    int f2=find(v);
    if(r[f1]<r[f2]){//如果u的祖先等價低於v的祖先就等級優先 
        par[f1]=f2;
    }
    else{//否則相反 
        par[f2]=f1;
        if(r[f1]==r[f2]) r[f1]++;   //如果祖先等級相同優先前者等級加1 
    }
}
int Kruskal(int n,int m){
    int edge=0,sum=0;
    sort(a+1,a+n+1,cmp);//對所有邊按距離從小到大排序 
    for(int i=1;i<=n&&edge!=m-1;i++){//當求到m-1條邊說明已經聯通 
        if(find(a[i].a)!=find(a[i].b)){//對每條邊找祖先如果不同說明沒聯通可以合併祖先 
            merge(a[i].a,a[i].b);
            sum+=a[i].price;//總路程加這條邊的距離 
            edge++;//統計邊數 
        }
    }
    if(edge<m-1) sum=-1;//如果邊少於m-1說明是無法聯通的 
    return sum;
}
int main()
{
    int n,m,ans;
    //freopen("in.txt","r",stdin);
    while(cin>>n>>m&&n){
        init(m);
        for(int i=1;i<=n;i++)
        {
            cin>>a[i].a>>a[i].b>>a[i].price;
        }
        ans=Kruskal(n,m);
        if(ans==-1) cout<<"?\n";
        else cout<<ans<<endl;
    } 
    return 0;
}