图_最小生成树_Kruskal算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvxiangyu11/article/details/79771494
导读请参考:《算法导论》(第三版)p367

这里使用不相交集(并查集)算法,有需要的请参考《算法导论》p324(比较有趣的问题,还会引出二分染色图,竞赛中出现也比较多)

#include<iostream>
#include<ctime>
#include<vector>

/*
This programme is realize bulid a gragh min tree by Kruskal Algotithm
Editor:Xiangyu Lv
email:[email protected]
frist-edit-time:2018年3月30日12:46:13
ALL RIGHTS RESERVED!
*/
#define DEBUG

using namespace std;

typedef int Vertex;
typedef int Weight;

class GraphListAndEdge {
public:
	explicit GraphListAndEdge() {
		edgeList.resize(0);
		list.resize(0);
		nameList.resize(0);
	}

	void insert(Vertex v0, Vertex v1, Weight w) {
		int v0Loc = find(v0);
		if (v0Loc == -1)
			v0Loc = _new_node(v0);
		int v1Loc = find(v1);
		if (v1Loc == -1)
			v1Loc = _new_node(v1);

		EdgeNode * newEN = new EdgeNode;
		newEN->Loc = v1Loc;
		newEN->BratherNode = list[v0Loc].jointEdge;
		newEN->weight = w;
		newEN->vertex = v1;
		list[v0Loc].jointEdge = newEN;
		size_t i = 0;
		for (; i < edgeList.size(); i++) {
			if (edgeList[i].weight > w) {//升序排序
				break;
			}
		}
		EdgeListNode newELN;
		newELN.v0Loc = v0Loc;
		newELN.v1Loc = v1Loc;
		newELN.weight = w;
		if (edgeList.size()!=0)
			edgeList.insert(edgeList.begin() + i , newELN);
		else
			edgeList.push_back(newELN);
	}

	void KruskalTinyStree() {
		MINweight = 0;
		disjointSet.resize(nameList.size(), -1);
		know.resize(nameList.size(), false);
		for (size_t i = 0; i < edgeList.size(); i++) {
			//if (know[edgeList[i].v0Loc] == false || know[edgeList[i].v1Loc] == false) {
				if (!_disjoint_if_joint(edgeList[i].v0Loc, edgeList[i].v1Loc)) {//不相交
					_disjoint_union(edgeList[i].v0Loc, edgeList[i].v1Loc);
#ifdef DEBUG
					cout << "连接:" << list[edgeList[i].v0Loc].vertex << " " << list[edgeList[i].v1Loc].vertex << endl;
#endif // DEBUG
					know[edgeList[i].v0Loc] = true;
					know[edgeList[i].v1Loc] = true;
					MINweight += edgeList[i].weight;
				}
			//}
		}

		//检测不是连通图
		for (size_t i = 0; i < list.size(); i++) {
			if (know[i] == false)
				cout << "存在不是连通图的一个点名称是:" <<list[i].vertex<< endl;
		}
		cout << "最小生成树的总权值是:" << MINweight << endl;

	}

private:
	struct EdgeNode
	{
		Vertex vertex;
		int Loc;
		Weight weight;
		EdgeNode * BratherNode;
	};
	struct ListStack
	{
		Vertex vertex;
		Weight weight;
		EdgeNode * jointEdge;
	};
	struct EdgeListNode
	{
		Weight weight;
		int v0Loc;
		int v1Loc;
	};

	vector<ListStack> list;
	vector<EdgeListNode> edgeList;
	vector<Vertex> nameList;
	vector<int> disjointSet;//用不相交集存每个树的集合
	vector<bool> know;
	int MINweight;
	int find(Vertex v0) {
		for (size_t i = 0; i < nameList.size(); i++)
		{
			if (nameList[i] == v0)
				return i;
		}
		return -1;
	}
	int _new_node(Vertex v0) {
		ListStack newStack;
		newStack.vertex = v0;
		newStack.jointEdge = nullptr;
		newStack.weight = 0;
		list.push_back(newStack);
		nameList.push_back(v0);
		return nameList.size() - 1;
	}
	bool _disjoint_if_joint(int v0loc, int v1loc) {//在同一个集合内返回真,否则返回假
#ifdef DEBUG
		cout << " 检测:" << v0loc << " " << v1loc << endl;
#endif // DEBUG
		if (_disjoint_find(v0loc) == _disjoint_find(v1loc))
			return true;
		return false;
	}

	void _disjoint_union(int v0loc, int v1loc) {//用启发式修改
		v0loc = _disjoint_find(v0loc);
		v1loc = _disjoint_find(v1loc);
		if (disjointSet[v0loc] < disjointSet[v1loc]) {//v0比v1深
			disjointSet[v1loc] = v0loc;
			disjointSet[v0loc]--;
		}
		else
			if (disjointSet[v0loc] == disjointSet[v1loc]) {
				disjointSet[v1loc] = v0loc;
				disjointSet[v0loc]--;
			}
			else {
				disjointSet[v0loc] = v1loc;
				disjointSet[v1loc]--;
			}
	}
	int _disjoint_find(int loc) {//不相交集收缩
		if (disjointSet[loc] > -1)
			return disjointSet[loc] = _disjoint_find(disjointSet[loc]);
		else
			return loc;
	}
};

int main() {
	GraphListAndEdge myGraph;
	int i = 0;
	cin >> i;
	for (int j = 0; j < i; j++) {
		Vertex v0, v1, w;
		cin >> v0 >> v1 >> w;
		myGraph.insert(v0, v1, w);
	}
	myGraph.KruskalTinyStree();
#ifdef DEBUG
	system("pause");
#endif // DEBUG
	return 0;
}
/*
28
1 2 4
2 1 4
1 8 8
8 1 8
2 8 11
8 2 11
2 3 8
3 2 8
3 9 2
9 3 2
9 8 7
8 9 7
8 7 1
7 8 1
9 7 6
7 9 6
7 6 2
6 7 2
3 6 4
6 3 4
3 4 7
4 3 7
4 6 14
6 4 14
4 5 9
5 4 9
5 6 10
6 5 10

output:
 检测:2 5
连接:8 7
 检测:5 2
 检测:3 4
连接:3 9
 检测:4 3
 检测:5 6
连接:7 6
 检测:6 5
 检测:0 1
连接:1 2
 检测:1 0
 检测:3 6
连接:3 6
 检测:6 3
 检测:4 5
 检测:5 4
 检测:4 2
 检测:2 4
 检测:3 7
连接:3 4
 检测:7 3
 检测:0 2
连接:1 8
 检测:2 0
 检测:1 3
 检测:3 1
 检测:7 8
连接:4 5
 检测:8 7
 检测:8 6
 检测:6 8
 检测:1 2
 检测:2 1
 检测:7 6
 检测:6 7
最小生成树的总权值是:37
*/


猜你喜欢

转载自blog.csdn.net/lvxiangyu11/article/details/79771494
今日推荐