【C++】图1

并查集

template <class T>
class UnionFindSet
{
public:
	UnionFindSet(size_t n)
		:_ufs(n, -1)
	{}

	void Union(int x1, int x2)
	{
		int root1 = FindRoot(x1);
		int root2 = FindRoot(x2);
		if (root1 == root2)
			return;
		if (root1 > root2)
			swap(root1, root2);
		_ufs[root1] += _ufs[root2];
		_ufs[root2] = root1;
	}

	int FindRoot(int x)
	{
		int parent = x;
		while (_ufs[parent] >= 0)
		{
			parent = _ufs[parent];
		}
		return parent;
	}

	bool InSet(int x1, int x2)
	{
		return FindRoot(x1) == FindRoot(x2);
	}

	size_t SetSize()
	{
		size_t size = 0;
		for (size_t i = 0; i < _ufs.size(); i++)
		{
			if (_ufs[i] < 0)
			{
				++size;
			}
		}
		return size;
	}
private:
	std::vector<T> _ufs;
};

路径压缩:

template <class T>
class UnionFindSet
{
public:
	UnionFindSet(size_t n)
		:_ufs(n, -1)
	{}

	void Union(int x1, int x2)
	{
		int root1 = FindRoot(x1);
		int root2 = FindRoot(x2);
		// 如果在一个集合里面就不需要合并
		if (root1 == root2)
			return;

		// 数据量小的合并到大的集合
		if (abs(_ufs[root1]) < abs(_ufs[root2]))
			std::swap(root1, root2);
		_ufs[root1] += _ufs[root2];
		_ufs[root2] = root1;
	}

	int FindRoot(int x)
	{
		int root = x;
		while (_ufs[root] >= 0)
		{
			root = _ufs[root];
		}
		// 路径压缩
		while (_ufs[x] >= 0)
		{
			int parent = _ufs[x];
			_ufs[x] = root;
			x = parent;
		}
		return root;
	}

	bool InSet(int x1, int x2)
	{
		return FindRoot(x1) == FindRoot(x2);
	}

	size_t SetSize()
	{
		size_t size = 0;
		for (size_t i = 0; i < _ufs.size(); i++)
		{
			if (_ufs[i] < 0)
			{
				++size;
			}
		}
		return size;
	}
private:
	std::vector<T> _ufs;
};

void UnionFindSetTest()
{
	UnionFindSet<int> ufs(10);
	ufs.Union(7, 6);
	ufs.Union(5, 4);
	ufs.Union(7, 5);
	ufs.Union(5, 2);
	ufs.Union(9, 6);
	ufs.Union(0, 1);
	ufs.Union(0, 3);
	ufs.Union(0, 7);

	for (int i = 0; i < 10; i++)
	{
		ufs.FindRoot(i);
	}
}

省份的数量
等式方程的可满足性

在这里插入图片描述
两种实现策略:矩阵和领接表

矩阵
在这里插入图片描述

领接表在这里插入图片描述
两者互补

namespace matrix
{
	template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
	class Graph
	{
	public:
		//图的创建:
		//1.IO输入 ---不方便测试
		//2.图结构关系写到文件
		//3.手动添加边
		Graph(const V* a, size_t n)
		{
			for (size_t j = 0; j < n; j++)
			{
				_vertexs.push_back(a[j]);
				_indexMap[a[j]] = j;
			}
			_matrix.resize(n);
			for (size_t i = 0; i < n; i++)
			{
				_matrix[i].resize(n, MAX_W);
			}
		}

		size_t GetVertexIndex(const V& v)
		{
			auto it = _indexMap.find(v);
			if (it != _indexMap.end())
			{
				return it->second;
			}
			else
			{
				//assert(false);
				throw invalid_argument("顶点不存在");
				return -1;
			}
		}
		void AddEdge(const V& src, const V& dst, const W& w)
		{
			size_t srci = GetVertexIndex(src);
			size_t dsti = GetVertexIndex(dst);
			_matrix[srci][dsti] = w;
			//无向图
			if (Direction == false)
			{
				_matrix[dsti][srci] = w;
			}
		}

		void Print()
		{
			//顶点
			for (size_t i = 0; i < _vertexs.size(); i++)
			{
				cout << i << "->" << _vertexs[i] << endl;
			}
			cout << endl;
			//矩阵
			printf("#");//所在的行列为顶点
			for (size_t i = 0; i < _vertexs.size(); i++)
				cout << " " << _vertexs[i];
			cout << endl;
			for (size_t i = 0; i < _matrix.size(); i++)
			{
				cout << _vertexs[i] << " ";
				for (size_t j = 0; j < _matrix.size(); j++)
				{
					if (_matrix[i][j] != MAX_W)
					{
						//cout << _vertexs[i] << "->" << _vertexs[j] << ": " << _matrix[i][j] << endl;
						cout << _matrix[i][j] << " ";
					}
					else
					{
						//cout << _vertexs[i] << "->" << _vertexs[j] << ": " << "*" << endl;
						cout << "* ";
					}
				}
				cout << endl;
			}
		}
	private:
		vector<V> _vertexs;			//顶点集合
		map<V, int> _indexMap;		//顶点映射
		vector<vector<W>> _matrix;	//邻接矩阵
	};

	void TestGraph1()
	{
		Graph<char, int, INT_MAX, true> g("abcd", 4);
		g.AddEdge('a', 'b', 1);
		g.AddEdge('a', 'c', 4);
		g.AddEdge('b', 'c', 3);
		g.AddEdge('b', 'b', 8);
		g.AddEdge('c', 'c', 7);
		g.AddEdge('c', 'b', 9);
		g.AddEdge('d', 'a', 2);
		g.AddEdge('d', 'b', 5);

		g.Print();
	}
}

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值