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

    定义

    在一给定的无向联通带权图(G = (V, E, W))中,((u, v)) 代表连接顶点 (u) 与顶点 (v) 的边,而 (w(u, v)) 代表此边的权重,若存在 (T)(E) 的子集,且为无循环图,使得 (w(T)) 最小,则此 (T)(G)最小生成树

    其中(w(T)=sumlimits_{(u,v)∈t} w(u,v))

    由定义易得,(T)中的边数为 顶点个数(-1)

    实现算法常用(Kruskal)(Prim)

    (Kruskal)算法

    将边按权值从小到大排序再依次放入图中,当整个图只有一个连通分量时,程序结束。

    实现方法

    • 1.找到(E)中最小边
    • 2.判断边的两点是否在同一连通分量中
    • 3.若在,舍弃此边,转1。
    • 4.若不在,添加此边,将端点所在连通分量合并。
    • 5.所有边全选完后,若选边数为n-1,则输出解,否则无解处理。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int EDG=1000010;
    const int VER=100010;
    int n,m;
    struct edge 
    {
    	int _start;
    	int _end;
    	int _weigh;
    } arc[EDG];/*结构体存边,便于排序*/ 
    bool cmp(edge a,edge b)
    {
    	return a._weigh<b._weigh;
    }
    int parent[VER];
    inline void init();
    inline int find(int x);
    int union_(int x,int y);
    inline bool search_(int x,int y);
    
    int main()
    {
    	init();
    	cin>>n>>m;
    	for(int i=1;i<=m;i++)
    	{
    		cin>>arc[i]._start>>arc[i]._end>>arc[i]._weigh;
    	}
    	if(m<n-1)//如果不够n-1条边,直接无解 
    	{
    		cout<<"orz";
    		return 0;
    	}
    	sort(arc+1,arc+1+m,cmp);//权值排序 
    	int num=0;
    	int ans=0;
    	for(int i=1;i<=m;i++)
    	{
    		if(!search_(arc[i]._start,arc[i]._end))//如果边的端点不在同一个连通分量中 
    		{
    			ans+=arc[i]._weigh;//选择这条边 
    			union_(arc[i]._end,arc[i]._start);//合并两个连通分量 
    			num++;//选择的边数 +1 
    		}
    	}
    	if(num==n-1)//最小生成树只可能有n-1条边 
    	{
    		cout<<ans;
    	}
    	else cout<<"orz";
    }
    
    /*----------并查集相关----------*/
    inline void init()
    {
    	for(int i=0;i<=VER;i++)
    	{
    		parent[i]=i;
    	}
    }
    inline int find(int x)
    {
    	int x_root=x;
    	while(x_root!=parent[x_root])
    	{
    		x_root=parent[x_root];
    	}
    	while(x!=x_root)
    	{
    		int tmp=parent[x];
    		parent[x]=x_root;
    		x=tmp;
    	}
    	return x_root;
    }
    int union_(int x,int y)
    {
    	int x_root=find(x);
    	int y_root=find(y);
    	if(x_root==y_root) return 0;
    	parent[x_root]=y_root;
    	return 1;
    }
    inline bool search_(int x,int y)
    {
    	return find(x)==find(y);
    }
    

    (Prim)算法

    其实就是(dijksrta)的变种,配合理解即可

    #include <bits/stdc++.h>
    using namespace std;
    const int INF=0x3f3f3f3f;
    int edg[1010][1010];
    int dis[100010];
    int vis[100010];
    int n;
    
    void prim()
    {
    	int sum=0;
    	memset(dis,0x3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	for(int i=1;i<=n;i++) dis[i]=edg[1][i];
    	vis[1]=1;
    	dis[1]=1;
    	for(int i=1;i<n;i++)
    	{
    		int minn=INF;
    		int u;
    		for(int j=1;j<=n;j++)
    		{
    			if(!vis[j]&&minn>dis[j])
    			{
    				u=j;
    				minn=dis[j];
    			}
    		}
    		vis[u]=1;
    		sum+=minn;
    		for(int j=1;j<=n;j++)
    		{
    			if(!vis[j]&&edg[u][j]<dis[j])
    			{
    				dis[j]=edg[u][j];
    			}
    		}
    	}
    	cout<<sum;
    }
    int main()
    {
    	cin>>n;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=n;j++)
    		{
    			cin>>edg[i][j];
    		}
    	}
    	prim();
    	return 0;
    }
    
  • 相关阅读:
    我是新手,我在学Android
    WAMP环境下(apache2.2.21+Php5.3.10)编写PHP扩展
    java中三种字符串正则匹配方式
    PHP扩展开发过程中的问题
    Android错误解决方法之:Debug certificate expired on
    Ubuntu下C++开发PHP开发扩展的注意事项
    我的笔试题
    很多时候,是否好好看完一本好书,对一个人的提升往往能达到质的区别
    C语言常用宏定义
    Linux下用C++开发PHP扩展
  • 原文地址:https://www.cnblogs.com/IzayoiMiku/p/13040398.html
Copyright © 2011-2022 走看看