zoukankan      html  css  js  c++  java
  • 【模板】最小生成树(prime、kruscal、prim堆优化)

    Description

    给出一个无向图,求出最小生成树,如果该图不连通,则输出orz

    Input

    第一行包含两个整数N、M,表示该图共有N个结点和M条无向边(N<=5000,M<=200000)
    接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi

    Output

    输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz

    Sample Input

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

    Sample Output

    7

    Hint

    【数据规模】
    对于20%的数据:N<=5,M<=20
    对于40%的数据:N<=50,M<=2500
    对于70%的数据:N<=500,M<=10000
    对于100%的数据:N<=5000,M<=200000


    0、题外话

    • 关于三种算法:
    • prim常用于稠密图,kruscal用于稀疏图,而prim堆优化在稀疏图中比kruskal跑得慢,在稠密图中用prim优化有点鸡肋。。。
    • 算法讲解

    1、Prime算法

    #include <iostream>
    #include <cstdio>
    #define inf 0x7fffffff
    using namespace std;
    int n,m,cnt,head[5005];
    struct node{int next,to,w;}e[400005];
    void addedge(int x,int y,int z){e[++cnt].to=y,e[cnt].w=z,e[cnt].next=head[x],head[x]=cnt;}
    int flag[5005],dist[5005];
    void prim()
    {
    	for(int i=1;i<=n;++i) dist[i]=inf; dist[1]=0;
    	int ans=0;
    	for(int i=1;i<=n;++i)
    	{
    		int minn=inf,k=-1;
    		for(int j=1;j<=n;++j)
    			if(dist[j]<minn&&!flag[j]) minn=dist[j],k=j;
    		if(k==-1){puts("orz"); return;}
    		flag[k]=1; ans+=dist[k];
    		for(int j=head[k];j;j=e[j].next)
    			if(!flag[e[j].to]&&dist[e[j].to]>e[j].w) dist[e[j].to]=e[j].w;
    	}
    	printf("%d
    ",ans);
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1,x,y,z;i<=m;++i) scanf("%d%d%d",&x,&y,&z),addedge(x,y,z),addedge(y,x,z);
    	prim();
    	return 0;
    }
    

    2、Kruskal算法

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    int n,m,ans,cnt,fa[5005];
    struct fdfdfd{int x,y,w;}e[200005];
    int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);}
    bool cmp(fdfdfd a,fdfdfd b){return a.w<b.w;}
    void kruskal()
    {
    	sort(e+1,e+m+1,cmp);
    	for(int i=1;i<=n;++i) fa[i]=i;
    	for(int i=1;i<=m;++i)
    	{
    		int fx=getfa(e[i].x),fy=getfa(e[i].y);
    		if(fx==fy) continue;
    		fa[fx]=fy; ans+=e[i].w; ++cnt;
    		if(cnt==n-1){printf("%d
    ",ans); return;}
    	}
    	puts("orz");
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;++i) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
    	kruskal();
    	return 0;
    }
    

    3、堆优化prim算法-STL实现

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    int cnt,n,m,ans,head[5005],dist[5005],flag[5005];
    struct node{int to,w,next;} e[400005];
    void addedge(int x,int y,int z){e[++cnt].to=y; e[cnt].w=z; e[cnt].next=head[x]; head[x]=cnt;}
    typedef pair <int,int> pii;
    priority_queue <pii,vector<pii>,greater<pii> > q;
    void prim()
    {
        memset(dist,0x7f,sizeof(dist)); dist[1]=0;
        cnt=0;
        q.push(make_pair(0,1));
        while(!q.empty()&&cnt<n)
        {
            int d=q.top().first,u=q.top().second;
    		q.pop();
            if(flag[u]) continue;
            ++cnt; ans+=d; flag[u]=1;
            for(int i=head[u];i;i=e[i].next)
            	if(e[i].w<dist[e[i].to]) dist[e[i].to]=e[i].w,q.push(make_pair(e[i].w,e[i].to));
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1,x,y,z;i<=m;++i) scanf("%d%d%d",&x,&y,&z),addedge(x,y,z),addedge(y,x,z);
        prim();
        if(cnt==n) printf("%d
    ",ans);
        else puts("orz");
    }
    
  • 相关阅读:
    不可错过的几款GitHub开源项目
    Android OTG之USB转串口模块通讯
    Multiple dex files define Lokhttp3/internal/wsWebSocketProtocol
    npm install安装依赖包失败
    Jquery 添加删除属性、添加删除class、添加删除Css(转载)
    jquery 获取一个元素的坐标位置
    Axure9 最新版的授权码(转)
    js实现上移 下移 置顶 置底操作
    iframe子页面获取父页面元素和window对象
    window.onresize与$(window).resize()的用法
  • 原文地址:https://www.cnblogs.com/wuwendongxi/p/13549961.html
Copyright © 2011-2022 走看看