zoukankan      html  css  js  c++  java
  • c++ 最小生成树

    关于最小生成树

    最小生成树,简写为 MST
    相信大家一定记得这样一个定理:把 N 个点用 N-1 条边连接,形成的连通块一定是一棵树
    当然一个 N 个点联通图肯定有大于等于 N-1 条边,而最小生成树就是从中选 N-1 条边以联通 N 个点
    并且这 N-1 条边的边权和是所有方案中最小的

    Kruskal

    Kruskal 基于贪心和并查集,首先按照边权从小到大排序
    然后枚举每一条边,如果 (Find(u_i) e Find(v_i)),就 (ans+=w_i)并把(u_i)(v_i)所在集合合并
    若已经选了 n-1 条边,就输出 ans
    具体看代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    inline char gc(){
    	static char buf[100000],*S=buf,*T=buf;
    	return S==T&&(T=(S=buf)+fread(buf,1,100000,stdin),S==T)?EOF:*S++;
    }
    inline int read(){
        static char c=gc();register int f=1,x=0;
        for(;c>'9'||c<'0';c=gc()) c==45?f=-1:1;
        for(;c>'/'&&c<':';c=gc()) x=(x<<3)+(x<<1)+(c^48);
        return x*f;
    }
    struct tr{int u,v;LL val;}t[400002];
    int n,m;
    int f[100002],h[100002],st,ed,tot=0;LL ans=0;
    inline int find(int x){while(f[x]!=x) x=f[x]=f[f[x]];return x;}
    inline void merge(int x,int y){
    	if(h[x]==h[y]) ++h[x],f[y]=x;
    	else if(h[x]<h[y]) f[x]=y;
    	else f[y]=x;
    } 
    void qs(int l,int r){
    	int i=l,j=r;tr mid=t[rand()%(r-l)+l];
    	while(i<=j){
    		while(t[i].val<mid.val) i++;
    		while(t[j].val>mid.val) j--;
    		if(i<=j){
    			swap(t[i],t[j]);
    			i++,j--;
    		}
    	}
    	if(i<r) qs(i,r);
    	if(j>l) qs(l,j);
    }
    int main(){
    	n=read(),m=read();
    	for(int i=1;i<=n;i++) f[i]=i;
    	for(int i=1;i<=m;i++) t[i].u=read(),t[i].v=read(),t[i].val=1ll*read();
    	qs(1,m);
    	for(int i=1;i<=m;i++){
    		st=find(t[i].u);
    		ed=find(t[i].v);
    		if(st!=ed){
    			ans+=t[i].val;
    			merge(st,ed);
    			tot++;
    			if(tot+1==n){
    				printf("%lld",ans);
    				return 0;
    			}
    		}
    	}
    	puts("-1");
    }
    

    时间复杂度(O(mlog n+mlog m)) 适用于稀疏图

    Prim

    Prim 适用于稠密图,思路接近 Dijkstra :每次选一个花费最小的点进行拓展

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5005;
    int n,m,cnt,ans,g[N][N],vis[N],cost[N];
    int main() {
    	memset(g,100,sizeof(g));
    	scanf("%d%d",&n,&m);
    	for(int i=1,u,v,w;i<=m;i++) {
    		scanf("%d%d%d",&u,&v,&w);
    		if(g[u][v]>w)g[u][v]=w;
    		g[v][u]=g[u][v];
    	}
    	for(int i=2;i<=n;i++)cost[i]=g[1][i];
    	vis[1]=1;
    	for(int C=1,mn,p;C<n;C++) {
    		mn=2100000000,p=-1;
    		for(int i=1;i<=n;i++)
    		if(!vis[i] && cost[i]<mn)mn=cost[i],p=i;
    		if(p==-1)return printf("Err"),0;
    		vis[p]=1,ans+=mn;
    		for(int i=1;i<=n;i++)
    			if(!vis[i] && g[p][i]<cost[i])
    				cost[i]=g[p][i];
    	}
    	printf("%d",ans);
    } 
    

    时间复杂度(O(n^2))

    关于堆优化

    其实比较鸡肋:修改的次数太多了,使得复杂度没什么差别

  • 相关阅读:
    创建数据库的那些事
    同步、异步、阻塞、非阻塞我的理解
    Openfire MultiUserChat 多用户聊天 消息发送
    JAVA 随机字符串
    OF 同步异步问题的改进
    Openfire S2S 监听与消息处理
    MySQL FEDERATED 存储引擎
    一个S2S通信中的同步、异步问题的解决
    Openfire Monitoring/jinglenodes plugin error
    Java Cache System JCS(一) 使用方法
  • 原文地址:https://www.cnblogs.com/KonjakLAF/p/13194437.html
Copyright © 2011-2022 走看看