最小生成树学习总结(二)

解决最小生成树的算法有两个:
1.Prim(普里姆算法)算法
2.Krustral(克鲁斯卡尔算法)

两个算法的比较:

1.Kruskal:
(1).将所有边从小到大加入,在此过程中判断是否构成回路
(2).使用数据结构:并查集(不会并查集点我)
(3).时间复杂度:O(ElogE)
(4).适用于稀疏图
2.Prim:
(1).从任一节点出发,不断扩展
(2).使用数据结构:堆
(3).时间复杂度:O(ElogV) 或 O(VlogV+E)(斐波那契堆)
(4).适用于密集图
(5).若不用堆则时间复杂度为O(V2 )

两个算法的形象演示

我们还是用题目直接看吧:洛谷3366

题目描述:
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz。
输入格式: 第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi
输出格式:
输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz
输入样例:

4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3

输出样例:

7

#include<iostream>//最小生成树(普利姆算法) 
#include<cstdio> 
#include<cstring>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<cmath>
#include<algorithm>
#define lson node<<1,st,mid
#define rson node<<1|1,mid+1,ed
#define mem(a,x) memset(a,x,sizeof(a))
#define me(a) memset(a,0,sizeof(a))
#define IOS ios::sync_with_stdio(false)
#define lowbit(x) x&(-x)
typedef long long ll;
const ll mod=1e9+7;
const ll INF=0x3f3f3f3f;
const ll maxn=1e6+5;
const double pi = acos(-1.0);
using namespace std;
int n,m;
struct code{
	int to;
	int w;
	int next;
}edge[maxn<<1];
int head[maxn],dist[maxn];
bool vis[maxn];
int cnt;
void intn(){
	cnt=0;
	mem(head,-1);
	mem(vis,false);
	mem(dist,INF);
}
void add(int u,int v,int w){
	cnt++;
	edge[cnt].to=v;
	edge[cnt].w=w;
	edge[cnt].next=head[u];
	head[u]=cnt;
}
int ans=0;
int prim(int u){
	int tot=0,k=u;
	for(int i=head[u];i!=-1;i=edge[i].next){
		dist[edge[i].to]=min(dist[edge[i].to],edge[i].w);
	}
	dist[k]=0;
	vis [k]=true;
	while(++tot<n){
		int minn=INF;
		vis[k]=true;
		for(int i=1;i<=n;i++){
			if(!vis[i]&&minn>dist[i]){
				minn=dist[i];
				k=i;
			}
		}
		ans+=minn;
		for(int i=head[k];i!=-1;i=edge[i].next){
			int v=edge[i].to;
			if(dist[v]>edge[i].w&&!vis[v]){
				dist[v]=edge[i].w;
			}
		}
	}
	return ans;
}
int main(){
	IOS;
	cin>>n>>m;
	intn();
	while(m--){
		int u,v,w;
		cin>>u>>v>>w;
		add(u,v,w);add(v,u,w);
	}
	int res=prim(1);
	bool flag=false;
	for(int i=1;i<=n;i++){
		if(dist[i]>=INF){
			cout<<"orz"<<endl;
			flag=true;
		}
	}
	if(!flag) cout<<res<<endl;
}

#include<iostream>//最小生成树(克鲁斯卡尔算法) 
#include<cstdio> 
#include<cstring>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<cmath>
#include<algorithm>
#define lson node<<1,st,mid
#define rson node<<1|1,mid+1,ed
#define mem(a,x) memset(a,x,sizeof(a))
#define me(a) memset(a,0,sizeof(a))
#define IOS ios::sync_with_stdio(false)
#define lowbit(x) x&(-x)
typedef long long ll;
const ll mod=1e9+7;
const ll INF=0x3f3f3f3f;
const ll maxn=1e6+5;
const double pi = acos(-1.0);
using namespace std;
struct code{
	int u,v,w;
}edge[maxn<<1];
int n,cnt,m;
int F[maxn];
void intn(){
	cnt=0;
	mem(F,-1);
}
int find(int x){
	if(F[x]==-1) return x;
	else return F[x]=find(F[x]); 
}
bool cmp(code a,code b){
	return a.w<b.w; 
}
int Kruskal(){
	int ans=0,bs=0;
	sort(edge,edge+cnt,cmp);
	for(int i=0;i<cnt;i++){
		int u=edge[i].u;
		int v=edge[i].v;
		int w=edge[i].w;
		int t1=find(u);
		int t2=find(v);
		if(t1!=t2){
			ans+=w;
			F[t1]=t2;
			bs++;
		}
		if(bs==n-1) break;
	}
	if(bs<n-1) return -1;
	else return ans;
}
void add(int u,int v,int w){
	cnt++;
	edge[cnt].v=v;
	edge[cnt].w=w;
	edge[cnt].u=u;
}
int main(){
	IOS;
	intn();
	cin>>n>>m;
	while(m--){
		int u,v,w;
		cin>>u>>v>>w;
		add(u,v,w);add(v,u,w);
	}
	int x=Kruskal();
	if(x==-1) cout<<"orz"<<endl;
	else cout<<x<<endl; 
}  
posted @ 2019-12-11 16:59  许久九  阅读(39)  评论(0)    收藏  举报