最小生成树review

题目链接
最小生成树

Kruskal 适合点多的稀疏图O(mlogm)

#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+9;
int n,m,s,cnt;
int fa[N];

struct pp {
    int l,r,w;//w是路径长度
    bool operator <(const pp &b)
    {
    	return w < b.w;
    }
}a[N];


inline int find(int x) {     //并查集的模板,一直往上找父节点
    return x==fa[x]?x:fa[x] = find(fa[x]);
}
void kruskal() {
    
    for(int i=1; i<=m; i++) {
        int v=find(a[i].l),u=find(a[i].r);//找父节点,看是否同根
        if(v==u)continue;          //已经被接在了树上,就不用接了
        ++cnt;
        s+=a[i].w;
        fa[u]=v;
        if(cnt==n-1) return;
    }
}
int main() {
    ios::sync_with_stdio(false),cin.tie(0);
    cin>>n>>m;

    for(int i=1; i<=n; i++)
    	fa[i]=i;//初始化,自己是自己的父节点

    for(int i=1; i<=m; i++)
        cin>>a[i].l>>a[i].r>>a[i].w;
    
    sort(a+1,a+m+1);
    kruskal();

    if(cnt==n-1)
    	cout<<s;
    else cout<<"orz";

    return 0;
}

prim堆优化,O(nlogn)-适合边多稠密图 (被卡可达到n2)

#include<bits/stdc++.h>
#define R register int//优化,可忽略
#define P pair <int,int>
using namespace std;
const int N = 1e5+9;

int k,n,m;
int cnt,sum,dis[N],vis[N];
vector <int> E[2*N];//存点
vector <int> W[2*N];//存边
inline void add(int u,int v,int w) {
	E[u].push_back(v);//存点
	W[u].push_back(w);//存边
}

priority_queue <P,vector<P>,greater<P> > q;  //递减
inline void prim() {            //神似dijskra

	memset(dis,127,sizeof(dis));    //初始化
	dis[1]=0;
	q.push({dis[1],1});

	while(!q.empty()&&cnt<n) {
		int d=q.top().first,u=q.top().second;
		q.pop();

		if(vis[u]) continue;
		cnt++;
		sum+=d;  
		vis[u]=1;   //处理重复和求距离
		
		for(R i=0; i<E[u].size(); i++)//dijskra这里是循环找中界点,这里则直接找与该点相邻的边
	   	if(W[u][i]<dis[E[u][i]]){
			dis[E[u][i]]=W[u][i];
           	q.push({dis[E[u][i]],E[u][i]});
		}
	}
}
int main() {
	scanf("%d%d",&n,&m);
	for(R i=1; i<=m; i++) {
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		add(a,b,c);
		add(b,a,c);
	}
	prim();
	if (cnt==n)printf("%d",sum);
	else printf("orz");
}

posted @ 2022-04-30 17:17  InsiApple  阅读(75)  评论(0编辑  收藏  举报