• C++数据结构之最小生成树


    最小生成树是图的一部分,一般求最小生成树用Prim算法和Kruskal算法。

    对于Prim算法,思想是:在访问过的顶点和未访问的顶点之间选择权值最小的边。Prim算法是基于顶点的操作,适合于顶点较少,边较多的图。

    对于Kruskal算法,思想是:直接从图中选择权值最小的边,并且已选择的边不能构成连通图。Kruskal算法是基于边的操作,适合于边较少,顶点较多的图。

    Prim算法,在此我用了关联容器pair作为边的存储结构:

    //普里姆算法
    int Prim(const int G[][VNUM], vector<pair<int, int> > &edge)
    {
    	int w = 0;						//权重
    	vector<int> visited(VNUM, 0);	//已访问节点集合				
    	//初始化
    	visited[0] = 1;					//0号节点已访问			
    	//循环VNUM-1次
    	int u, v;
    	for(int number = 1; number < VNUM; ++number)
    	{	
    		int min = M;
    		for(int i = 0; i != VNUM; ++i) //一次循环有一个节点入栈
    		{
    			if(visited[i] == 1)
    			{
    				for(int j = 1; j != VNUM; ++j)			//判断边(i, j)的权值,i为已访问节点,j为未访问节点
    				{
    					
    					if(visited[j] == 0 && G[i][j] < min)
    					{
    						min = G[i][j];
    						v = i;
    						u = j;
    					}
    				}
    			}
    		}
    		w += G[v][u];
    		visited[u] = 1;
    		edge[number-1].first = v;
    		edge[number-1].second = u;
    	}
    	return w;
    }

    克鲁斯卡尔算法的最小生成树结构用并查集表示,并查集在次主要用来判断已选择的边是否构成连通图,如果对应顶点x,y的FindRoot()操作返回的结果相同,即他们的根相同,则能够成连通图,说明选择的边不满足条件。

    //并查集结构
    class DisjointSet{
    public:
    	vector<int> father;
    	DisjointSet(int VNUM){
    		father.resize(VNUM, -1);
    	}
    	int FindRoot(int x)
    	{
    		while(father[x] >= 0)
    			x = father[x];
    		return x;
    	}
    	void Union(int x, int y)
    	{
    		father[FindRoot(x)] = FindRoot(y);
    	}
    };
    //Kruskal
    int Kruskal(const int G[][VNUM], vector<pair<int, int> > &edge)
    {
    	int min = M;
    	int w = 0;
    	int v, u;
    	DisjointSet V(VNUM);
    	for(int num = 0; num != VNUM-1; ++num)
    	{
    		min = M;
    		for(int i = 0; i != VNUM; ++i)
    		{
    			for(int j = 0; j != VNUM; ++j)
    			{
    				if(G[i][j] < min && V.FindRoot(i) != V.FindRoot(j))
    				{
    					min = G[i][j];
    					v = i;
    					u = j;
    				}
    			}
    		}
    		w += G[u][v];
    		V.Union(u, v);
    		edge[num].first = v;
    		edge[num].second = u;
    	}
    	return w;
    }


    下面是主程序:

     

    /*************************
    Date	: 2013-9-20
    Author	: DVD0423
    Function: 无向图的最小生成树
    ******************&******/
    #include <iostream>
    #include <vector>
    #include <utility>
    using namespace std;
    const int M = 10;		//两节点无边权值用M表示
    const int VNUM = 6;
    
    int Prim(const int G[][VNUM], vector<pair<int, int> > &edge);
    int Kruskal(const int G[][VNUM], vector<pair<int, int> > &edge);
    
    int main()
    {
    	const int G[VNUM][VNUM] = {
    	M, 9, 1, M, 7, 2,
    	9, M, 5, 1, M, 6,  
    	1, 5, M, 4, 2, 6,
    	M, 1, 4, M, 9, 3,
    	7, M, 2, 9, M, M,
    	2, 6, 6, 3, M, M
    	};
    	vector<pair<int, int> > edge(VNUM-1);
    
    	//Prim
    	cout<<"普里姆算法:"<<endl;	
    	cout<<"总路径长度:"<<Prim(G, edge)<<endl;
    	for(int i = 0; i != VNUM-1; ++i)
    		cout<<"("<<edge[i].first<<", "<<edge[i].second<<")"<<endl;
    
    	//Kruskal
    	cout<<"克鲁斯卡尔算法:"<<endl;
    	cout<<"总路径长度:"<<Kruskal(G, edge)<<endl;
    	for(int i = 0; i != VNUM-1; ++i)
    		cout<<"("<<edge[i].first<<", "<<edge[i].second<<")"<<endl;
    
    	return 0;
    }


    输出结果如下:


  • 相关阅读:
    javascript功能插件大集合
    基于Swiper插件的简单轮播图的实现
    LeetCode24. 两两交换链表中的节点
    530. 二叉搜索树的最小绝对差
    416. 分割等和子集
    GAN ——Generative Adversarial Network 理解与推导(一)
    面试题 02.08. 环路检测(返回环路开头节点)
    141.环形链表-LeetCode
    357. 计算各个位数不同的数字个数 ——LeetCode
    LSTM的理解
  • 原文地址:https://www.cnblogs.com/riskyer/p/3333820.html
Copyright © 2020-2023  润新知