图论之最小生成树

来源:互联网 发布:中国社交网络使用排名 编辑:程序博客网 时间:2024/06/01 08:00

  这次的生成树是匆忙写出来的,所以代码有点难看!我用的是kruskal算法,我认为这个比prim算法好理解一点!就是每次找未知边的最小边,在判断此边的两个点在已知边下是否连通——这里就要用到我刚说的不相交集类,如果连通则放弃,不连通则加人以知边,做完N-1次即可,下面是代码:


#include<iostream>#include<stdio.h>#include<vector>#include<queue>using namespace std;class Disjsets{private:vector<int>s;public:Disjsets(int num):s(num){for(int i=0;i<s.size();i++)s[i]=-1;}int find(int x){if(s[x]<0)return x;elsereturn s[x]=find(s[x]);}void unionSets(int root1,int root2){if(s[root1]<s[root2])s[root1]=root2;else{if(s[root1]==s[root2])s[root1]--;s[root2]=root1;}}void makeDisj(){for(int i=0;i<s.size();i++)s[i]=-1;}};class graph{  struct  Edge{   int e1,e2,w;   Edge(int u,int v,int w):e1(u),e2(v),w(w){}   friend bool operator <(Edge v1,Edge v2)   {       return v1.e1>v2.e1;   }  };  struct weight{int ver;int num;int w;weight(){};weight(int v,int n,int ww=0):ver(v),num(n),w(ww){}   friend bool operator <(const weight v,const weight v1){               returnv.w>v1.w;}   };   class vertex{public:int num;         //点在图中的编号vector<weight>L;      //与此顶点相关的边vertex():num(0){}void merge(int x,int y){   weight p(num,x,y);   L.push_back(p);}};vector<vertex> v;public:graph(int x){v.resize(x);for(int i=0;i<x;i++)v[i].num=i+1;}void merge(int x,int y,int weight){if(x!=y)v[x-1].merge(y,weight);}int kruskal(){priority_queue<weight>qw;priority_queue<Edge>Ed;int n=v.size();Disjsets D(n+1);int e1,e2,sum=0;for(int i=0;i<n;i++)            {                 int siz=v[i].L.size();              for(int j=0;j<siz;j++){   weight tmp=v[i].L[j];   qw.push(tmp);}            }weight wg;int edge =1;for(;edge<n&&!qw.empty();edge++){while(D.find(qw.top().num)==D.find(qw.top().ver))               {                                      qw.pop();                                      if(qw.empty())                                        return -1;               }wg=qw.top();       e1=wg.ver;     e2=wg.num;     sum+=wg.w;                qw.pop();                Edge E(e1,e2,wg.w);                Ed.push(E);                D.unionSets(e1,e2);     }        if(edge==n)        {while(!Ed.empty()){Edge ed=Ed.top();Ed.pop();cout<<"("<<ed.e1<<","<<ed.e2<<","<<ed.w<<") ";}cout<<endl;        return sum;        }        return -1;    }};int main(){   freopen("in.txt","r",stdin);   freopen("out.txt","w",stdout);    int n,m;    while(cin>>m>>n&&m)    {        graph G(n);        int u,v,w;        while(m--)        {            cin>>u>>v>>w;            G.merge(u,v,w);            G.merge(v,u,w);        }      int sum=G.kruskal();      sum==-1?cout<<"?"<<endl:cout<<sum<<endl;    }   fclose(stdin);   fclose(stdout);   return 0;}
然后是in.txt的数据:

12 7
1 2 2
1 4 1
2 4 3
2 5 10
3 1 4
3 5 6
4 6 8
4 7 4
4 5 2
4 3 2
5 7 6
7 6 1
12 7
1 4 1
1 2 2
1 3 4
2 4 3
2 5 10
3 4 2
3 6 5
4 5 7
4 6 8
4 7 4
5 7 6
6 7 1
3 3
1 2 1
1 3 2
2 3 4
1 3
2 3 2
0 100


最后是out.txt的结果:

(1,4,1) (1,2,2) (4,3,2) (4,7,4) (4,5,2) (7,6,1) 
12
(1,4,1) (1,2,2) (4,3,2) (4,7,4) (7,6,1) (7,5,6) 
16
(1,2,1) (1,3,2) 
3
?

结果OK ,另外,交hdu的畅通工程那题也是ac的,说明确实没有问题!

6 0