这次的生成树是匆忙写出来的,所以代码有点难看!我用的是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的,说明确实没有问题!