生成树

最小生成树:在无向图中,连接所有的点,不形成环,使所有的边权值和最小的树  

算法有:prim算法: dijkstra算法类似(dis[i]的含义不同,dijkstra中是起点,prim中是已经访问过的所有点) 稠密图时使用 O(V^2)
kruskal算法:并查集思想,每次都找到最小的边,判断这两个边连接的点是不是在同一个集合中,如果不是就连接起来 稀疏图时使用 O(ElogE)

struct node{
	int v,dis;
	node(int _v,int _dis) : v(_v),dis(_dis){}
};
vector<node> adj[maxn];
int dis[maxn],vis[maxn];
int n,m,st,ed;
void prim(int st){
	//树的总权值,以及当前所有的连接好了的边

	 for(int i=0;i<n;i++){
	 	int u=-1,mini=INF; //与dijkstra是不是超级像!!!!!
		 for(int j=0;j<n;j++){
		 	if(mini>dis[j]&&vis[j]==0) {
		 		mini=dis[j];
				 u=j;
			 }
		 } 
		 if(u==-1) return;
		 vis[u]=1;
		 ans+=dis[u]; //!!!!!啊啊啊记住这个 
		 for(int j=0;j<adj[u].size();j++){
		 	int id=adj[u][j].v;
		 	int diss=adj[u][j].dis;
		 	if(!vis[id]&&dis[id]>diss){
		 		dis[id]=diss;//!!!! 
			 }
		 }
	 }
	 
}

kruskal

struct edge{
	int from,to;
	int dis;
}E[maxn]; 

int fa[maxn];
int findfather(int x){
	if(x!=fa[x]) return findfather(fa[x]);
	return fa[x];
}
bool cmp(edge a,edge b){
	return a.dis<b.dis;
}
void kruskal(int n,int m){
	//n是顶点数,m是边数
	for(int i=0;i<n;i++) fa[i]=i;  //先弄这个
	fill(dis,dis+maxn,INF);
	memset(vis,0,sizeof(vis));
	dis[0]=0;
	int ans=0,numedge=0; //这里才有!!总的权值和现在有了的边
	 sort(E,E+m,cmp); //对边进行排序
	 for(int i=0;i<m;i++){
	 	int fa1=findfather(E[i].from);
	 	int fa2=findfather(E[i].to);
	 	if(fa1!=fa2){
	 		fa[fa2]=fa1;
	 		numedge++;
	 		ans+=E[i].dis;
	 		if(numedge==n-1) break; //!!!!!!!如果边数已经够了的话就可以break了 
		 }
	 }
	 if(numedge!=n-1) {
	 	cout<<"error no liantong"<<endl;
	 	return;
	 } 
	  else{
	  	cout<<ans<<endl;
	  	return;
	  }
} 

 

上一篇:最小生成树(Prim和Kruscal)


下一篇:ACwing(基础)--- Prim