最小生成树

1. Problem Description

如题,给出一个无向图,求出最小生成树

2. Input

第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)

接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi

3. Output

输出包含一个数,即最小生成树的各边的长度之和;

输入样例#1:

4 5 1 2 2 1 3 2 1 4 3 2 3 4 3 4 3 输出样例#1:

7

  

 

  Kruskal算法证明:如果某个连通图属于最小生成树,那么所有从外部连接到该连通图的边中的一条最短的边必然属于最小生成树。所以不难发现,当最小生成树被拆分成彼此独立的若干个连通分量的时候,所有能够连接任意两个连通分量的边中的一条最短边必然属于最小生成树

  尤其注意变量total。

代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int par[51000],rnk[5100];
 5 const int inf=1<<30;
 6 int n,m;
 7 struct edge{
 8     int u,v,cost;
 9 }a[201000]; 
10 bool cmp(const edge&a,const edge &b){
11     return a.cost<b.cost;
12 }
13 int find(int x){
14     if(par[x]==x)    return x;
15     else {
16         return par[x]=find(par[x]);
17     }
18 }
19 void unite(int x,int y){
20     x=find(x),y=find(y);
21     if(x==y) return ;
22     if(rnk[x]<rnk[y])    par[x]=y;
23     else {
24         par[y]=x;
25         if(rnk[x]==rnk[y])    rnk[x]++;
26     }
27 }
28 bool same(int x,int y) {
29     return find(x)==find(y);
30 }
31 int main(){
32     cin>>n>>m;
33     for(int i=0;i<n;i++){
34         par[i]=i;
35     } 
36     for(int i=0;i<m;i++){
37     scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].cost);
38     }
39     sort(a,a+m,cmp);
40     ll ans=0;edge e;    int total=0; 
41     for(int i=0;i<m;i++){
42         e=a[i];
43         if(!same(e.u,e.v)){
44             unite(e.u,e.v);
45             ans+=e.cost;
46             total++;
47             if(total==n-1)break;
48         }
49         
50     }
51     bool flag=1;
52     for(int i=1;i<n;i++){
53         if(find(i)!=find(0)){
54             flag=0;
55             break;
56         }
57     }
58     if(flag)    cout<<ans<<endl;
59     else cout<<"orz\n";
60     return 0;
61 }

 

posted @ 2018-10-16 13:54  清酒令  阅读(254)  评论(0编辑  收藏  举报