这次的生成树是匆忙写出来的,所以代码有点难看!我用的是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; else return 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) { return v.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的,说明确实没有问题!
原文:http://blog.csdn.net/alop_daoyan/article/details/22613921