对于任给的一张无向带权连通图,求出其最小生成树(C++)

Posted 唐火

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对于任给的一张无向带权连通图,求出其最小生成树(C++)相关的知识,希望对你有一定的参考价值。

对于任给的一张无向带权连通图,求出其最小生成树。

题目要求:

(1)编程创建一幅图
(2)输出创建的图
(3)编写Prim算法代码,实现图的最小生成树求解,且输出最小生成树
(4)编写Kruskal算法代码,实现图的最小生成树求解,且输出最小生成树
(5)编写菜单,允许用户选择相应操作

代码如下:

#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
const int maxVertexNum = 30;//最大顶点数
const int noEdge = 99999999;//用来记录两个顶点之间没有边
const int ERROR = -1;//发生错误


class Graph

private :

	class Edge
	
	public :
		int v1;
		int v2;
		int w;
	;

	int edgeNum;//边数
	int vertexNum;//顶点数
	int vertexs[maxVertexNum][maxVertexNum];//邻接矩阵
	bool vis[maxVertexNum];//用来标记是否访问过该顶点
	int dist[maxVertexNum];//prim算法中用来记录该结点离最小生成树的距离
	int parent[maxVertexNum];//prim算法中用到
	Edge edge[maxVertexNum];//用来记录边,方便输出
	int totalWeight;//最小权重和
	int set[maxVertexNum];//kruskal算法中,集合数组,利用并查集算法,来判断是否构成回路
	Edge kEdge[maxVertexNum];//kruskal算法中所用,用来记录创建的图的信息,在用kruskal算法时,不是用邻接矩阵存储的图,而是用了这个结构体数组来存储

public:

	void menu()
	
		char c;
		while (true)
		
			cout << "--------邻接矩阵存储的图--------------" << endl;
			cout << "--------输入 c 创建图-----------------" << endl;
			cout << "--------输入 p 输出图-----------------" << endl;
			cout << "--------输入 r 使用prim算法-----------" << endl;
			cout << "--------输入 k 使用kruskal算法--------" << endl;
			cout << "--------输入 e 退出程序---------------" << endl;
			cout << "---------顶点从0开始------------------" << endl;
			cin >> c;
			switch (c)
			
			case 'c':
				buildGraph();
				cout << "创建完毕,按任意键继续" << endl;
				c = getchar();//吃回车
				c = getchar();//吃任意键
				system("cls");//刷新屏幕
				break;
			case 'p':
				printGraph();
				cout << "输出完毕,按任意键继续" << endl;
				c = getchar();
				c = getchar();
				system("cls");
				break;
			case 'r':
				prim();
				cout << "输出完毕,按任意键继续" << endl;
				c = getchar();
				c = getchar();
				system("cls");
				break;
			case 'k':
				kruskal();
				cout << "输出完毕,按任意键继续" << endl;
				c = getchar();
				c = getchar();
				system("cls");
				break;
			case 'e':
				return;
			

		
	

	Graph() :vertexNum(0), edgeNum(0)
	
		initVis();
		for (int i = 0; i < maxVertexNum; i++)
		
			for (int j = 0; j < maxVertexNum; j++)
			
				vertexs[i][j] = noEdge;
			
		
	


private:

	void initSet()
	
		for (int i = 0; i < vertexNum; i++) set[i] = i;
	

	void Union(int root1, int root2)
	

		int x = Find(root1);
		int y = Find(root2);
		if (x != y)
		
			set[x] = y;
		
	

	int Find(int x)
	
		if (set[x] != x) return Find(set[x]);
		else return x;
	

	void initVis()
	
		for (int i = 0; i < maxVertexNum; i++)
		
			vis[i] = false;
		
	





	void buildGraph()
	
		cout << "请输入节点数和边数" << endl;
		cin >> vertexNum >> edgeNum;
		int e1, e2;
		int w;
		for (int i = 0; i < edgeNum; i++)
		
			cin >> e1 >> e2>>w;
			vertexs[e1][e2] = w;
			vertexs[e2][e1] = w;
			kEdge[i].v1 = e1;
			kEdge[i].v2 = e2;
			kEdge[i].w = w;
		

	

	
	void printGraph()
	
		for (int i = 0; i < vertexNum; i++)
		
			vis[i] = true;
			for (int j = 0; j < vertexNum; j++)
			
				if (!vis[j]&&vertexs[i][j] != noEdge)
				
					cout << i << " - " << j <<" = "<<vertexs[i][j]<< endl;
				
			
		
		initVis();
	

	int findMinDist()
	
		int minVertex;
		int minDist = noEdge;
		for (int i = 0; i < vertexNum; i++)
		
			if (dist[i] != 0 && dist[i] < minDist)
			
				minDist = dist[i];
				minVertex = i;
			
		
		if (minDist < noEdge) return minVertex;
		else return ERROR;
	


	void prim()
	
		
		for (int i = 0; i < vertexNum; i++)
		
			dist[i] = vertexs[0][i];
			parent[i] = 0;
		
		totalWeight = 0;
		int cnt = 0;
		dist[0] = 0;
		parent[0] = -1;
		cnt++;
		int v;
		while (true)
		
			v = findMinDist();
			if (v == ERROR) break;
			edge[cnt].v1 = parent[v];
			edge[cnt].v2 = v;
			edge[cnt].w = dist[v];
			totalWeight += dist[v];
			dist[v] = 0;
			cnt++;

			for (int w = 0; w < vertexNum; w++)
			
				if (dist[w] != 0 && vertexs[v][w] < noEdge)
				
					dist[w] = vertexs[v][w];
					parent[w] = v;
				
			
		

		if (cnt < vertexNum)
		
			cout << "此图不连通" << endl;
		
		else
		
			for (int i = 1; i < cnt; i++)
			
				cout << edge[i].v1 << " - " << edge[i].v2 << " = " << edge[i].w << endl;
			
			cout <<"totalWeight = " <<totalWeight << endl;
		
	

	//所有普通类成员函数,都不能以函数指针的方式作为其他函数的入口函数。
	//所以这里的cmp函数要加上static
	static bool cmp(Edge a, Edge b)
	
		return a.w < b.w;
	


	void kruskal()
	
		initSet();
		sort(kEdge,kEdge+edgeNum,cmp);
		int cnt = 0;
		int idx = 0;
		totalWeight = 0;
		while (cnt < vertexNum - 1 && idx < edgeNum)
		
			int v1 = kEdge[idx].v1;
			int v2 = kEdge[idx].v2;

			if (Find(v1) != Find(v2))
			
				edge[cnt].v1 = v1;
				edge[cnt].v2 = v2;
				edge[cnt].w = kEdge[cnt].w;
				totalWeight += edge[cnt].w;
				cnt++;
				Union(v1, v2);
			
			idx++;
		

		if (cnt < vertexNum - 1)
		
			cout << "此图不连通" << endl;
		
		else
		
			for (int i = 0; i < vertexNum - 1; i++)
			
				cout << edge[i].v1 << " - " << edge[i].v2 << " = " << edge[i].w << endl;
			
			cout << "totalWeight = " << totalWeight << endl;
		

	



;


int main()

	Graph g;
	g.menu();
	return 0;

示例:




以上是关于对于任给的一张无向带权连通图,求出其最小生成树(C++)的主要内容,如果未能解决你的问题,请参考以下文章

ACM第四站————最小生成树(普里姆算法)

无向带权图的最小生成树算法——Prim及Kruskal算法思路

[算法] 带权图

克鲁斯卡尔

最小生成树 prime kruskal

图——最小生成树