ACM模板二:树、图、并查集、覆盖

目录

〇,全文说明、宏定义代码

一,二叉树

1,代码

2,测试代码

二,树状数组、线段树

1,代码

2,测试代码

三,多叉树、RMQ、LCA

1,代码

2,测试代码

四,DancingLink、Covering

1,代码

2,测试代码

五,匈牙利算法

1,代码

2,测试代码

六,并查集、无向图、最小生成树Kruskal

1,代码

2,测试代码

七,最小生成树Prim

1,代码

2,测试代码

八,有向图、单源最短路径、连通分量、拓扑排序

1,代码

2,测试代码

九,网格图、回路链路、路径重建

1,代码

2,测试代码


〇,全文说明、宏定义代码

类里面和宏定义处都有接口注释,因为宏不体现具体参数,所以注释以类里面的为准。

代码工程结构:

  • 每一章的第一节《代码》可以独立编译运行(本地要加LOCAL宏)
  • 每一章的第二节《测试代码》搭配第〇章的代码和本章第一节的代码可以编译运行并测试成功
  • 所有模板文章的第〇章的代码和其他章第一节的《代码》全部汇总起来可以编译运行

宏定义代码:


#define LOCAL //力扣不要本行代码,其他OJ随意

///(1)二叉树///
#define MaxDepth BinaryTree::maxDepth//求二叉树的深度,根节点深度是1
#define MinDepth BinaryTree::minDepth//叶子节点的最小深度
#define PreorderTraversal BinaryTree::preorderTraversal//二叉树的前序遍历
#define PostorderTraversal BinaryTree::postorderTraversal//二叉树的后序遍历
#define InorderTraversal BinaryTree::inorderTraversal//二叉树的中序遍历
#define LevelOrderTraversal BinaryTree::levelOrderTraversal//二叉树的层序遍历
#define BuildTreePre BinaryTree::buildTreePre//根据前序和中序重建二叉树,假设没有重复数字
#define BuildTreePost BinaryTree::buildTreePost//根据中序和后序重建二叉树,假设没有重复数字
#define CountNodes BinaryTree::countNodes//求节点个数
#define CopyTree BinaryTree::copyTree//拷贝二叉树
#define IsSameTree BinaryTree::isSameTree//判断两棵二叉树是否全等
#define InvertTree BinaryTree::invertTree//左右翻转二叉树

///(2)树状数组、线段树///
// TreeArray 树状数组
// TreeArray2D 二维树状数组
// SegmentTree 线段树

///(3)多叉树、RMQ、LCA///
#define MultiTreePreorder MultiTree::preorder //多叉树前序遍历
#define MultiTreePostorder MultiTree::postorder //多叉树后序遍历
#define EdgesToMultiTree MultiTree::edgesToMultiTree//输入无向图,构造多叉生成树
// TreeWithId 略。//把二叉树或多叉树转成id形式的树,前序遍历,从0开始编号
// RMQ 略。
// LCA 略。

///(4)DancingLink、Covering///
// DancingLink 略。精确覆盖算法
#define GetEdgeCover Covering::getEdgeCover//给定一个2n个点的图,选出n条边,刚好覆盖这2n个点

///(5)匈牙利算法///
#define HungarianMaxMatch Hungarian().maxMatch //求二分图最大匹配,v是一边的点集,adjaList的每条边都恰好有一个点在v中

///(6.1)并查集///
// Union 略。并查集
// UnionDif 略。
// Vunion 略。

///(6.2)无向图///
#define GetAdjaListFromTree UndirectedGraph::getAdjaList //输入二叉树,转化成无向图的邻接表,没有权值,节点编号是先序遍历的编号,默认从0开始
#define EdgesToBinaryTree UndirectedGraph::edgesToBinaryTree //输入无环无向图,生成任意一棵二叉树,val存放原id,节点编号是从0开始依次编号
#define UndirectedEdgeToFatherList UndirectedGraph::undirectedEdgeToFatherList //无向拓扑排序,输入无向无环图{{1,2}{1,3}{4,3}}和指定根1,输出父节点表{4:3, 3:1, 2:1}
#define HasUndirectedCircle UndirectedGraph::hasUndirectedCircle //判断无向图是否有环
#define IsCompleteGraph UndirectedGraph::isCompleteGraph //判断是不是k-正则图
#define IsTwoDivGraph UndirectedGraph::isTwoDivGraph //判断是不是二分图

///(6.3)最小生成树Kruskal///
#define KruskalMinCostTree Kruskal::kruskalMinCostTree

///(7)最小生成树Prim///
#define PrimminCostTree Prim::minCostConnectPoints


///(8.1)有向图///
#define ReverseGraph DirectedGraph::reverseGraph//构建有向图的反向图
#define GetLongestPath DirectedGraph::getLongestPath//求有向无环图中的最长路径长度,出参nextNode是每个点的后继,len是每个点出发的最长路径长度
#define HasDirectedCircle DirectedGraph::hasCircle//根据有向图的邻接表判断是否有环

///(8.2)单源最短路径///
#define DijskraShortestPath Dijskra::shortestPath//求最短路,适用于不存在负权值的边的图
#define BellmanFordShortestPath BellmanFord::shortestPath//求最短路,适用于不存在负权值的环的图
#define SPFAShortestPath SPFA::shortestPath//求最短路,适用于不存在负权值的环的图

///(8.3)不区分有向图和无向图的通用操作///
#define GetSubGraph GraphOpt::getSubGraph//根据点集取子图

///(8.4)连通分量、拓扑排序///
#define SemiConnectComponent SemiConnect::semiConnectComponent//半连通分量分割
#define ConnectComponent KosarajuStrongConnect::connectComponent//Kosaraju算法,强连通分量分割
#define GetPointGraph KosarajuStrongConnect::getPointGraph//强连通分量缩点
// TarjanUndirect 略。Tarjan算法,双连通分量分割
// TarjanStrongConnect 略。Tarjan算法,强连通分量分割
#define TopoSortNoCircle DirectedTopoSort::topoSortNoCircle //有向无环图拓扑排序,输入n=3,g.edges={{0,1}{0,2}{1,2}}, 输出{0,1,2},有环则输出为空
#define TopoSort DirectedTopoSort::topoSort //有向图拓扑排序


///(9.1)网格图///
// GridGraph 略

///(9.2)回路或链路///
// Hierholzer 略。欧拉回路或链路
// Hamilton 略。哈密顿回路或链路

///(9.3)路径重建///
// ReBuild 略。路径重建

一,二叉树

1,代码


#ifdef LOCAL
#ifndef struct_TreeNode
#define struct_TreeNode
struct TreeNode {
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode() : val(0), left(nullptr), right(nullptr) {}
	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
	TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};
#endif
#endif

class BinaryTree
{
public:
	//求二叉树的深度,根节点深度是1
	static int maxDepth(TreeNode* root) {
		if (!root)return 0;
		return max(maxDepth(root->left), maxDepth(root->right)) + 1;
	}
	//叶子节点的最小深度
	static int minDepth(TreeNode* root) {
		if (!root)return 0;
		return min_depth(root);
	}
	//二叉树的前序遍历
	static vector<int> preorderTraversal(TreeNode* root) {
		vector<int>v1;
		if (root == NULL)return v1;
		v1.insert(v1.end(), root->val);
		vector<int>v2 = preorderTraversal(root->left);
		v1.insert(v1.end(), v2.begin(), v2.end());
		v2 = preorderTraversal(root->right);
		v1.insert(v1.end(), v2.begin(), v2.end());
		return v1;
	}
	//二叉树的后序遍历
	static vector<int> postorderTraversal(TreeNode* root) {
		vector<int>v1;
		if (root == NULL)return v1;
		vector<int>v2 = postorderTraversal(root->left);
		v1.insert(v1.end(), v2.begin(), v2.end());
		v2 = postorderTraversal(root->right);
		v1.insert(v1.end(), v2.begin(), v2.end());
		v1.insert(v1.end(), root->val);
		return v1;
	}
	//二叉树的中序遍历
	static vector<int> inorderTraversal(TreeNode* root) {
		vector<int>v1;
		if (root == NULL)return v1;
		v1 = inorderTraversal(root->left);
		v1.insert(v1.end(), root->val);
		vector<int>v2 = inorderTraversal(root->right);
		v1.insert(v1.end(), v2.begin(), v2.end());
		return v1;
	}
	//二叉树的层序遍历
	static vector<vector<int>> levelOrderTraversal(TreeNode* root) {
		vector<vector<int>>ans;
		if (!root)return ans;
		vector<vector<TreeNode*>>v;
		vector<TreeNode*>tmp;
		vector<int>tmpans;
		tmp.push_back(root);
		v.push_back(tmp);
		bfs(v);
		for (int i = 0; i < v.size(); i++) {
			tmpans.resize(v[i].size());
			for (int j = 0; j < v[i].size(); j++)tmpans[j] = v[i][j]->val;
			ans.push_back(tmpans);
		}
		return ans;
	}
	//根据前序和中序重建二叉树,假设没有重复数字
	static TreeNode* buildTreePre(vector<int>& preorder, vector<int>& inorder) {
		return build_tree(preorder, 0, inorder, 0, inorder.size());
	}
	//根据中序和后序重建二叉树,假设没有重复数字
	static TreeNode* buildTreePost(vector<int>& inorder, vector<int>& postorder) {
		return build_tree2(postorder, 0, inorder, 0, inorder.size());
	}
	//求节点个数
	static int countNodes(TreeNode* root) {
		if (!root)return 0;
		return countNodes(root->left) + countNodes(root->right) + 1;
	}
	//拷贝二叉树
	static TreeNode* copyTree(TreeNode* root)
	{
		if (!root)return root;
		return new TreeNode(root->val, copyTree(root->left), copyTree(root->right));
	}
	//判断两棵二叉树是否全等
	static bool isSameTree(TreeNode* r1, TreeNode* r2)
	{
		if (r1 == NULL && r2 == NULL)return true;
		if (r1 == NULL || r2 == NULL)return false;
		if (r1->val != r2->val)return false;
		return isSameTree(r1->left, r2->left) && isSameTree(r1->right, r2->right);
	}
	//左右翻转二叉树
	static TreeNode* invertTree(TreeNode* root) {
		if (!root)return root;
		TreeNode* p = root->left, *q = root->right;
		root->left = q, root->right = p;
		invertTree(p);
		invertTree(q);
		return root;
	}
private:
	static int min_depth(TreeNode* root) {
		if (!root)return 1234567890;
		if (!root->left && !root->right)return 1;
		return min(min_depth(root->left), min_depth(root->right)) + 1;
	}
	static void bfs(vector<vector<TreeNode*>>&v) {
		vector<TreeNode*>v1 = *(v.end() - 1);
		vector<TreeNode*>v2;
		for (int i = 0; i < v1.size(); i++) {
			if (v1[i]->left)v2.push_back(v1[i]->left);
			if (v1[i]->right)v2.push_back(v1[i]->right);
		}
		if (v2.empty())return;
		v.push_back(v2);
		bfs(v);
	}
	static TreeNode* build_tree(vector<int>& preorder, int s1, vector<int>& inorder, int s2, int len) {
		if (len <= 0)return NULL;
		TreeNode* ans = new TreeNode;
		ans->val = preorder[s1];
		auto loc = find(inorder.begin() + s2, inorder.begin() + s2 + len, preorder[s1]);
		ans->left = build_tree(preorder, s1 + 1, inorder, s2, loc - inorder.begin() - s2);
		ans->right = build_tree(preorder, loc - inorder.begin() - s2 + s1 + 1, inorder, loc - inorder.begin() + 1, len - (loc - inorder.begin() - s2) - 1);
		return ans;
	}
	static TreeNode* build_tree2(vector<int>& postorder, int s1, vector<int>& inorder, int s2, int len) {
		if (len <= 0)return NULL;
		TreeNode* ans = new TreeNode;
		ans->val = postorder[s1 + len - 1];
		auto loc = find(inorder.begin() + s2, inorder.begin() + s2 + len, postorder[s1 + len - 1]);
		ans->left = build_tree2(postorder, s1, inorder, s2, loc - inorder.begin() - s2);
		ans->right = build_tree2(postorder, loc - inorder.begin() - s2 + s1, inorder, loc - inorder.begin() + 1, len - (loc - inorder.begin() - s2) - 1);
		return ans;
	}
};

2,测试代码



template<typename T>
static bool IsSame(const T &a, const T &b)
{
	return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() - v2.size())return false;
	for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
	return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T,T2>&p1, const pair<T, T2>&p2)
{
	return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}

#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}


bool testBinaryTree()
{
	TreeNode t1(1), t2(2), t3(3), t4(4);
	t1.left = &t2, t1.right = &t3, t2.left = &t4;
	auto p = &t1;
	EXPECT_EQ(MaxDepth(p), 3);
	EXPECT_EQ(MinDepth(p), 2);
	vector<int>pre{ 1, 2, 4, 3 }, post{ 4, 2, 3, 1 }, inorder{ 4, 2, 1, 3 };
	EXPECT_EQ(PreorderTraversal(p), pre);
	EXPECT_EQ(PostorderTraversal(p), post);
	EXPECT_EQ(InorderTraversal(p), inorder);
	auto p2 = BuildTreePre(pre, inorder);
	EXPECT_EQ(IsSameTree(p, p2), true);
	p2 = BuildTreePost(inorder, post);
	EXPECT_EQ(IsSameTree(p, p2), true);
	EXPECT_EQ(CountNodes(p), 4);
	p2 = CopyTree(p);
	EXPECT_EQ(IsSameTree(p, p2), true);
	InvertTree(p2);
	EXPECT_EQ(IsSameTree(p, p2), false);
	InvertTree(p2);
	EXPECT_EQ(IsSameTree(p, p2), true);
	return true;
}

int main()
{
	if (testBinaryTree())cout << "test succ!";
	return 0;
}

二,树状数组、线段树

1,代码


template<int maxLen = 100000>
class TreeArray
{
public:
	TreeArray(int len)//len是元素实际数量,元素id范围是[1,n]
	{
		this->n = len;
		memset(c, 0, sizeof(int)*(len + 1));
	}
	void add(int i, int x)
	{
		while (i <= n)
		{
			c[i] += x;
			i += (i&(-i));
		}
	}
	int getSum(int i)
	{
		int s = 0;
		while (i)
		{
			s += c[i];
			i -= (i&(-i));
		}
		return s;
	}
private:
	int n;
	int c[maxLen+5];
};

template<int maxLen = 1000>
class TreeArray2D
{
public:
	TreeArray2D(int len)//len是元素实际数量,元素id范围是[1,n]*[1,n]
	{
		this->n = len;
		for (int i = 0; i <= n; i++)memset(c[i], 0, sizeof(int)*(n + 1));
	}
	void add(int x, int y, int a = 1)
	{
		for (int i = x; i <= n; i += (i&(-i)))
			for (int j = y; j <= n; j += (j&(-j)))c[i][j] += a;
	}
	int getSum(int x, int y)
	{
		int s = 0;
		for (int i = x; i > 0; i -= (i&(-i)))
			for (int j = y; j > 0; j -= (j&(-j)))
				s += c[i][j];
		return s;
	}
private:
	int n;
	int c[maxLen +5][maxLen +5];
};

//type=0,1,2,3,4分别表示sum型、min型、max型、minId型、maxId型线段树
//maxLen是元素最大数量
template<int type, int maxLen = 100000, typename T = int>
class SegmentTreeBase
{
public:
	T* getData()//先调getData更新数据再调build
	{
		return num;
	}
	void build(int len)//len是元素实际数量,元素id范围是[1,n]
	{
		this->n = len;
		build(1, 1, n);
	}
	void update(int uplace, T value)//1<=uplace<=n
	{
		num[uplace] = value;
		update(1, 1, n, uplace);
	}
	T query(int x, int y)//1<=x<=y<=n
	{
		return query(1, 1, n, x, y);
	}
protected:
	template<typename T2>
	inline T2 op(T2 a, T2 b)
	{
		if (type == 3)return num[a] < num[b] ? a : b;
		if (type == 4)return num[a] > num[b] ? a : b;
		if (type == 0)return a + b;
		return type == 1 ? min(a, b) : max(a, b);
	}
	void build(int key, int low, int high)
	{
		if (low == high)
		{
			ans[key] = type > 2 ? low : num[low];
			return;
		}
		int mid = (low + high) / 2;
		build(key * 2, low, mid);
		build(key * 2 + 1, mid + 1, high);
		ans[key] = op(ans[key * 2], ans[key * 2 + 1]);
	}
	void update(int key, int low, int high, int uplace)
	{
		if (low == high)
		{
			ans[key] = type > 2 ? low : num[low];
			return;
		}
		int mid = (low + high) / 2;
		if (uplace <= mid)update(key * 2, low, mid, uplace);
		else update(key * 2 + 1, mid + 1, high, uplace);
		ans[key] = op(ans[key * 2], ans[key * 2 + 1]);
	}
	T query(int key, int low, int high, int x, int y)
	{
		if (low == x && high == y)return ans[key];
		int mid = (low + high) / 2;
		if (mid < x)return query(key * 2 + 1, mid + 1, high, x, y);
		if (mid >= y)return query(key * 2, low, mid, x, y);
		T a = query(key * 2, low, mid, x, mid);
		T b = query(key * 2 + 1, mid + 1, high, mid + 1, y);
		return  op(a, b);
	}
protected:
	int n;
	T num[maxLen + 1];
	T ans[maxLen * 4 + 10];
};
//sum型线段树拓展,支持查询前缀和
template<int maxLen = 100000, typename T = int>
class SegmentTreeTypeSum :public SegmentTreeBase<0, maxLen, T>
{
	using BASE = SegmentTreeBase<0, maxLen, T>;
public:
	int queryPreSum(T x)
	{
		return queryPreSum(1, 1, BASE::n, x);
	}
private:
	int queryPreSum(int key, int low, int high, T x)
	{
		if (low == high)return low;
		int mid = (low + high) / 2;
		if (x <= BASE::ans[key * 2])return queryPreSum(key * 2, low, mid, x);
		return queryPreSum(key * 2 + 1, mid + 1, high, x - BASE::ans[key * 2]);
	}
};
//5种线段树拓展,支持区间更新,区间查询
template<int type, int maxLen = 100000, typename T = int, T invalid = -1>
class SegmentTree :public SegmentTreeBase<type, maxLen, T>
{
	using BASE = SegmentTreeBase<type, maxLen, T>;
public:
	void build(int len)//len是元素实际数量,元素id范围是[1,n]
	{
		BASE::n = len;
		build(1, 1, BASE::n);
	}
	void update(int uplace, T value)//1<=uplace<=n,覆盖父类函数
	{
		update(uplace, uplace, value);
	}
	void update(int x, int y, T value)//1<=x<=y<=n
	{
		update(1, 1, BASE::n, x, y, value);
	}
	T query(int x, int y)//1<=x<=y<=n
	{
		return query(1, 1, BASE::n, x, y);
	}
private:
	static inline T opMulti(T a, int num)
	{
		if (!type)return a * num;
		return a;
	}
	void build(int key, int low, int high)
	{
		if (low == high)
		{
			BASE::ans[key] = type > 2 ? low : BASE::num[low];
			lazy[key] = invalid;
			return;
		}
		int mid = (low + high) / 2;
		build(key * 2, low, mid);
		build(key * 2 + 1, mid + 1, high);
		BASE::ans[key] = BASE::op(BASE::ans[key * 2], BASE::ans[key * 2 + 1]);
		lazy[key] = invalid;
	}
	void update(int key, int low, int high, int x, int y, T value)
	{
		if (low == x && high == y)
		{
			BASE::ans[key] = type > 2 ? x : opMulti(value, high - low + 1);
			lazy[key] = value;
			if (x == y)BASE::num[x] = value;
			return;
		}
		if (lazy[key] != invalid)down(key, low, high);
		int mid = (low + high) / 2;
		if (mid < x)update(key * 2 + 1, mid + 1, high, x, y, value);
		else if (mid >= y)update(key * 2, low, mid, x, y, value);
		else
		{
			update(key * 2, low, mid, x, mid, value);
			update(key * 2 + 1, mid + 1, high, mid + 1, y, value);
		}
		BASE::ans[key] = BASE::op(BASE::ans[key * 2], BASE::ans[key * 2 + 1]);
	}
	void down(int key, int low, int high)
	{
		int mid = (low + high) / 2;
		BASE::ans[key * 2] = type > 2 ? low : opMulti(lazy[key], mid - low + 1);
		BASE::ans[key * 2 + 1] = type > 2 ? high : opMulti(lazy[key], high - mid);
		lazy[key * 2] = lazy[key];
		lazy[key * 2 + 1] = lazy[key];
		lazy[key] = invalid;
	}
	T query(int key, int low, int high, int x, int y)
	{
		if (low == x && high == y)return BASE::ans[key];
		if (lazy[key] != invalid) {
			return type > 2 ? x : opMulti(lazy[key], y - x + 1);
		}
		int mid = (low + high) / 2;
		if (mid < x)return query(key * 2 + 1, mid + 1, high, x, y);
		if (mid >= y)return query(key * 2, low, mid, x, y);
		T a = query(key * 2, low, mid, x, mid);
		T b = query(key * 2 + 1, mid + 1, high, mid + 1, y);
		return BASE::op(a, b);
	}
private:
	T lazy[maxLen * 4 + 10];
};

2,测试代码


template<typename T>
static bool IsSame(const T &a, const T &b)
{
	return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() - v2.size())return false;
	for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
	return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T,T2>&p1, const pair<T, T2>&p2)
{
	return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}

#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}

bool testTreeArray()
{
	TreeArray<> t(100);
	t.add(1, 5);
	t.add(3, 10);
	EXPECT_EQ(t.getSum(1), 5);
	EXPECT_EQ(t.getSum(100), 15);
	return true;
}
bool testSegmentTree()
{
	SegmentTreeTypeSum<10000> st;
	int* num = st.getData();
	num[1] = 3, num[2] = 4, num[3] = 2, num[4] = 6;
	st.build(4);
	st.update(1, 5); //5 4 2 6
	EXPECT_EQ(st.query(1, 3), 11);
	EXPECT_EQ(st.queryPreSum(5), 1);
	EXPECT_EQ(st.queryPreSum(9), 2);
	EXPECT_EQ(st.queryPreSum(11), 3);
	SegmentTree<1, 10000> stMin;
	num = stMin.getData();
	num[1] = 3, num[2] = 4, num[3] = 2, num[4] = 6;
	stMin.build(4);
	stMin.update(2, 3, 5);//3 5 5 6
	EXPECT_EQ(stMin.query(1, 4), 3);
	EXPECT_EQ(stMin.query(3, 4), 5);
	return true;
}
int main()
{
	if (testTreeArray() && testSegmentTree())cout << "test succ!";
	return 0;
}

三,多叉树、RMQ、LCA

1,代码


#ifdef LOCAL
#ifndef struct_TreeNode
#define struct_TreeNode
struct TreeNode {
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode() : val(0), left(nullptr), right(nullptr) {}
	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
	TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};
#endif
#endif

struct MultiTreeNode {
	int val = 0;
	vector<MultiTreeNode*>son{}; //son只存实际有的孩子,son可能为空
	MultiTreeNode() {}
	MultiTreeNode(int x) : val(x) {}
};

class MultiTree {
public:
	//多叉树前序遍历
	static vector<int> preorder(MultiTreeNode* root) {
		vector<int>v1, v2;
		if (root == NULL)return v1;
		v1.insert(v1.end(), root->val);
		for (int i = 0; i < root->son.size(); i++) {
			v2 = preorder(root->son[i]);
			v1.insert(v1.end(), v2.begin(), v2.end());
		}
		return v1;
	}
	//多叉树后序遍历
	static vector<int> postorder(MultiTreeNode* root) {
		vector<int>v1, v2;
		if (root == NULL)return v1;
		for (int i = 0; i < root->son.size(); i++) {
			v2 = postorder(root->son[i]);
			v1.insert(v1.end(), v2.begin(), v2.end());
		}
		v1.insert(v1.end(), root->val);
		return v1;
	}
	//输入连通的无向图的邻接表,构造一棵多叉生成树,val存放原id
	static MultiTreeNode* edgesToMultiTree(map<int, vector<int>>&m)
	{
		map<int, int>visit;
		map<int, MultiTreeNode*>mt;
		int x = m.begin()->first;
		queue<int>q;
		q.push(x);
		visit[x] = 1;
		mt[x] = new MultiTreeNode(x);
		while (!q.empty()) {
			int id = q.front();
			q.pop();
			for (auto x : m[id]) {
				if (visit[x])continue;
				q.push(x);
				visit[x] = 1;
				mt[id]->son.push_back(mt[x] = new MultiTreeNode(x));
			}
		}
		return mt[x];
	}
};

//把二叉树或多叉树转成id形式的树,前序遍历,从0开始编号
class TreeWithId
{
public:
	unordered_map<int, vector<int>>sons;//所有子节点的编号,其中根节点编号=0
	unordered_map<int, int>vals;//节点权值
	TreeWithId(TreeNode* root) {
		if (root)dfs(root);
	}
	TreeWithId(MultiTreeNode* root) {
		if (root)dfs(root);
	}
	unordered_map<TreeNode*, int>m;//原指针对应在新树中的编号
	unordered_map<MultiTreeNode*, int>m2;
private:	
	inline void dfs(TreeNode* root) {
		if (m.find(root) == m.end())m[root] = m.size();
		vals[m[root]] = root->val;
		if (root->left)dfs(root->left), sons[m[root]].push_back(m[root->left]);
		if (root->right)dfs(root->right), sons[m[root]].push_back(m[root->right]);
	}	
	inline void dfs(MultiTreeNode* root) {
		if (m2.find(root) == m2.end())m2[root] = m2.size();
		vals[m2[root]] = root->val;
		for (auto p : root->son)dfs(p), sons[m2[root]].push_back(m2[p]);
	}
};

template<typename T,bool flag>
class enableRMQ
{
public:
	typedef T retType;
};
template<typename T>
class enableRMQ<T, true>
{
public:
	typedef int retType;
};
//type=1是求最小值,=2是求最大值, =3是minId,=4是maxId
template<int type, typename T = int>
class RMQ
{
public:
	RMQ() {}
	RMQ(const vector<T>& data) {
		this->data = data;
		len = data.size();
		logLen = getLength(len + 5);
		init(data);
	}
	using retType = typename enableRMQ < T, (type>2) >::retType;
	inline retType getMinMax(int low, int high) { //求[low,high]内的最值或者最值的id,0<=low<=high<len
		if (type <= 2) {
			if (low == high)return v[low][0];
			int j = getLength(high - low) - 1;
			return opt(v[high + 1 - (1 << j)][j], v[low][j]);
		}
		else {
			if (low == high)return v[low][0];
			int j = getLength(high - low) - 1;
			return optId(v[high + 1 - (1 << j)][j], v[low][j]);
		}
	}
private:
	void init(const vector<T>& data) {
		v.resize(len);
		for (int i = 0; i < v.size(); i++) {
			v[i].resize(logLen);
			if (type <= 2)v[i][0] = data[i];
			else v[i][0] = i;
		}
		for (int j = 1; j < logLen; j++)
		{
			for (int i = 0; i < len; i++)
			{
				v[i][j] = v[i][j - 1];
				int k = i + (1 << (j - 1));
				if (k >= len)continue;
				if (type <= 2) v[i][j] = opt(v[i][j], v[k][j - 1]);
				else v[i][j] = optId(v[i][j], v[k][j - 1]);
			}
		}
	}
	static inline T opt(T x, T y) {
		return type == 1 ? min(x, y) : max(x, y);
	}
	inline T optId(int x, int y) {
		if (type == 3) {
			return data[x] < data[y] ? x : y;
		}
		return data[x] < data[y] ? y : x;
	}
	//二进制总位数
	static inline int getLength(int n) {
		int ans = 0;
		while (n)
		{
			n >>= 1;
			ans++;
		}
		return ans;
	}
private:
	vector<T>data;
	vector<vector<T>>v;
	int len, logLen;
};
class LCA {
public:
	LCA(TreeWithId tree) {
		int n = tree.vals.size();
		visitn.resize(n);
		visitDeep.resize(n * 2 - 1);
		ids.resize(n * 2 - 1);
		dfs(tree, 0, 1);
		opt = RMQ<3>(visitDeep);
	}
	//输入2个节点的id,输出最近公共祖先的id
	int getLca(int x, int y)
	{
		x = visitn[x], y = visitn[y];
		if (x > y)x ^= y ^= x ^= y;
		int minId = opt.getMinMax(x, y); //求最小深度对应的遍历数
		return ids[minId];
	}
private:
	void dfs(TreeWithId& tree, int k, int d)
	{
		for (auto p : tree.sons[k])
		{
			visitDeep[vnum] = d;
			ids[vnum++] = k;
			dfs(tree, p, d + 1);
		}
		visitn[k] = vnum; //存入每个点的任意一个遍历数
		visitDeep[vnum] = d; //存入遍历数对应的深度
		ids[vnum++] = k; //存入遍历数对应的节点id
	}
	vector<int> visitDeep;
	vector<int> visitn;
	vector<int> ids;
	int vnum = 0;
	RMQ<3>opt;
};

2,测试代码


template<typename T>
static bool IsSame(const T &a, const T &b)
{
	return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() - v2.size())return false;
	for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
	return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T,T2>&p1, const pair<T, T2>&p2)
{
	return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}

#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}

bool testTreeLca()
{
	//二叉树 TreeWithId+lca
	TreeNode* root = new TreeNode(3);
	root->left = new TreeNode(4);
	root->right = new TreeNode(6);
	root->left->left = new TreeNode(7);
	root->left->right = new TreeNode(8);
	root->right->right = new TreeNode(9);
	root->right->right->left = new TreeNode(11);
	// 3
	//    4
	//        7
	//        8
	//    6
	//        9
	//             11
	TreeWithId tree(root);
	// 0
	//    1
	//        2
	//        3
	//    4
	//        5
	//             6
	EXPECT_EQ(tree.m[root], 0);
	EXPECT_EQ(tree.m[root->right->right->left], 6);
	LCA lca(tree);
	EXPECT_EQ(lca.getLca(2, 6), 0); //即原多叉树中,7和11的最近公共祖先是3
	return true;
}
bool testMultiTreeLca()
{
	//多叉树 TreeWithId+lca
	MultiTreeNode * p1 = new MultiTreeNode(1);
	MultiTreeNode * p2 = new MultiTreeNode(2);
	MultiTreeNode * p3 = new MultiTreeNode(3);
	MultiTreeNode * p4 = new MultiTreeNode(4);
	MultiTreeNode * p5 = new MultiTreeNode(5);
	MultiTreeNode * p6 = new MultiTreeNode(6);
	MultiTreeNode * p7 = new MultiTreeNode(7);
	MultiTreeNode * p8 = new MultiTreeNode(8);
	MultiTreeNode * p100 = new MultiTreeNode(100);
	p1->son.push_back(p2);
	p1->son.push_back(p3);
	p1->son.push_back(p4);
	p2->son.push_back(p5);
	p2->son.push_back(p6);
	p2->son.push_back(p7);
	p4->son.push_back(p8);
	p4->son.push_back(p100);
	//1
	//  2
	//    5 6 7
	//  3
	//  4
	//    8 100
	EXPECT_EQ(MultiTreePreorder(p1), (vector<int>{1, 2, 5, 6, 7, 3, 4, 8, 100}));//先序
	EXPECT_EQ(MultiTreePostorder(p1), (vector<int>{5, 6, 7, 2, 3, 8, 100, 4, 1}));//后序
	TreeWithId tree{ p1 };
	EXPECT_EQ(tree.m2[p1], 0);  //这几行和上面的先序对应
	EXPECT_EQ(tree.m2[p2], 1);
	EXPECT_EQ(tree.m2[p5], 2);
	EXPECT_EQ(tree.m2[p6], 3); // tree.m2[px],y
	EXPECT_EQ(tree.m2[p7], 4); // x是先序的结果1, 2, 5, 6, 7, 3, 4, 8, 100
	EXPECT_EQ(tree.m2[p3], 5); // y是012345678
	EXPECT_EQ(tree.m2[p4], 6);
	EXPECT_EQ(tree.m2[p8], 7);
	EXPECT_EQ(tree.m2[p100], 8);
	LCA lca(tree);
	EXPECT_EQ(lca.getLca(tree.m2[p5], tree.m2[p100]), tree.m2[p1]); //即原多叉树中,5和100的最近公共祖先是1
}
bool testRMQ()
{
	vector<int>v{ 3,2,4,1,0,8,9 };
	RMQ<1>r1(v);//最小值
	EXPECT_EQ(r1.getMinMax(0, 0), 3);
	EXPECT_EQ(r1.getMinMax(2, 5), 0);//4 1 0 8
	RMQ<2>r2(v);//最大值
	EXPECT_EQ(r2.getMinMax(1, 1), 2);
	EXPECT_EQ(r2.getMinMax(2, 5), 8);//4 1 0 8
	RMQ<3>r3(v);//最小值id
	EXPECT_EQ(r3.getMinMax(3, 3), 3);
	EXPECT_EQ(r3.getMinMax(2, 5), 4);
	RMQ<4>r4(v);//最大值id
	EXPECT_EQ(r4.getMinMax(4, 4), 4);
	EXPECT_EQ(r4.getMinMax(2, 5), 5);
	return true;
}

int main()
{
	if (testTreeLca() && testMultiTreeLca() && testRMQ())cout << "test succ!";
	return 0;
}

四,DancingLink、Covering

1,代码

class DancingLink // 精确覆盖算法
{
public:
	DancingLink(int m, int n, int maxNum) //01矩阵的行、列、1的最大数量
	{
		this->m = m, this->n = n, maxNum += n + 1;
		rhead.resize(m + 1), nums.resize(n + 1);
		row.resize(maxNum), col.resize(maxNum);
		up.resize(maxNum), down.resize(maxNum), lef.resize(maxNum), rig.resize(maxNum);
		sc.resize(m), rows.resize(m);
		for (int i = 0; i <= n; i++)
		{
			up[i] = i, down[i] = i;
			lef[i] = i - 1, rig[i] = i + 1;
			row[i] = 0, col[i] = i, nums[i] = 0;
		}
		lef[0] = n, rig[n] = 0, nums[0] = INT_MAX;
		key = n;
		for (int i = 0; i <= m; i++)rhead[i] = 0;
	}
	void push(int r, int c)//新增坐标在(r,c)的一个节点
	{
		row[++key] = r, col[key] = c;
		up[key] = c, down[key] = down[c];
		up[down[c]] = key, down[c] = key;
		if (rhead[r] == 0)rhead[r] = lef[key] = rig[key] = key;
		else
		{
			lef[key] = rhead[r], rig[key] = rig[rhead[r]];
			lef[rig[rhead[r]]] = key, rig[rhead[r]] = key;
		}
		nums[c]++;
	}
	vector<vector<int>> getAllAns()
	{
		return dfs(false);
	}
	vector<int> getAnyAns()
	{
		auto v = dfs(true);
		if (v.size())return v[0];
		return vector<int>{};
	}
private:
	vector<vector<int>> dfs(bool onlyOne)
	{
		vector<vector<int>>ans;
		while (true) {
			if (rig[0] == 0) {
				rows.resize(rowsid);
				ans.push_back(rows);
				rows.resize(m);
				if (onlyOne)return ans;
			}
			int c = min_element(nums.begin() + 1, nums.end()) - nums.begin();
			if (rig[0] == 0)c = 0;
			del(c);
			while (true) {
				c = down[c];
				if (c > n)break;
				reback(col[c]);
				if (scid == 0)return ans;
				c = sc[--scid];
				rowsid--;
				for (int j = rig[c]; j != c; j = rig[j])reback(col[j]);
			}
			sc[scid++] = c;//记录选中id
			rows[rowsid++] = row[c];
			for (int j = rig[c]; j != c; j = rig[j])del(col[j]);
		}
		return ans;
	}
	inline void del(int c)//删除第c列的所有元素和他们所在行的所有元素
	{
		lef[rig[c]] = lef[c], rig[lef[c]] = rig[c];
		for (int i = down[c]; i != c; i = down[i])
			for (int j = rig[i]; j != i; j = rig[j])
				down[up[j]] = down[j], up[down[j]] = up[j], nums[col[j]]--;
		nums[c] = INT_MAX;
	}
	inline void reback(int c)//完全回退del操作
	{
		lef[rig[c]] = rig[lef[c]] = c, nums[c] = 0;
		for (int i = down[c]; i != c; i = down[i]) {
			for (int j = rig[i]; j != i; j = rig[j])
				down[up[j]] = up[down[j]] = j, nums[col[j]]++;
			nums[c]++;
		}
	}
private:
	int m, n, key;
	vector<int>row, col;//每个节点的行,列
	vector<int>rhead;//每行第一个节点的id
	vector<int>up, down, lef, rig;//每个节点上下左右的节点id
	vector<int>nums;//每一列的元素个数
	vector<int>sc;
	int scid = 0, rowsid = 0;
	vector<int>rows;//覆盖选中的行,值的范围是从1到m
};
#ifndef struct_UndirectedEdge
#define struct_UndirectedEdge
template<typename T = int>
struct UndirectedEdge
{
	UndirectedEdge() {
		a = b = dist = 0;
	};
	UndirectedEdge(const vector<int>&v) {
		a = v[0], b = v[1], dist = 0;
		if (v.size() > 2)dist = v[2];
	}
    bool operator==(const UndirectedEdge&e) const{
		return a == e.a && b == e.b && dist == e.dist;
	}
	int a;//端点a的id
	int b;//端点b的id
	T dist;//ab之间的距离
};
#endif
class Covering {
public:
	//给定一个2n个点的图,节点编号从0到2n-1,选出n条边,刚好覆盖这2n个点,返回所有的解
	static vector<vector<UndirectedEdge<int>>> getEdgeCover(int n, vector<UndirectedEdge<int>> &v)
	{
		DancingLink d(v.size(), n * 2, v.size() * 2);
		for (int i = 0; i < v.size(); i++) {
			d.push(i, v[i].a + 1);
			d.push(i, v[i].b + 1);
		}
		vector<vector<UndirectedEdge<int>>>ans;
		vector<vector<int>> vrow = d.getAllAns();
		for (auto vi : vrow) {
			vector<UndirectedEdge<int>>vans; //getNumFromId(v, vi)
			transform(vi.begin(), vi.end(), std::back_inserter(vans), [&](int id) {return v[id]; });
			ans.push_back(vans);
		}
		return ans;
	}
};

2,测试代码



template<typename T>
static bool IsSame(const T &a, const T &b)
{
	return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() - v2.size())return false;
	for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
	return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T, T2>&p1, const pair<T, T2>&p2)
{
	return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}

#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}

class SearchWithGroupSum //分组数字搜索算法
{
public:
	SearchWithGroupSum(vector<vector<int>>& gridGroup, int row, int col, int low, int high) :gridGroup{ gridGroup }, row{ row }, col{ col }, low{ low }, high{ high }
	{
		anti.resize(row*col);
		grid.resize(row*col);
		for (int g = 0; g < gridGroup.size(); g++) {
			for (int i = 0; i < gridGroup[g].size(); i++)anti[gridGroup[g][i]].push_back(g);
			maxNum += gridGroup[g].size();
		}
	}
	void setGrid(vector<int>& grid)//除了已知数字之外都填0,有type=1的格子时需要调用本接口
	{
		this->grid = grid;
	}
	void setType(vector<int>& type)//有type=1或-1的格子时需要调用本接口
	{
		this->type = type;
	}
	vector<int> getAnyAns()
	{
		int m = 0;
		for (auto k : type) {
			if (k == 0)m += high - low + 1;
			else if (k == 1)m += 1;
		}
		int n = gridGroup.size()*(high - low + 1) + row * col;
		DancingLink d(m, n, (maxNum + row * col)*(high - low + 1));
		int r = 0;
		map<int, int>mrow;
		mrow[0] = -1;
		for (int i = 0; i < row*col; i++) {
			if (type[i] == -1)continue;
			int lw = low, hh = high;
			if (type[i] == 1)lw = hh = grid[i];
			for (int x = lw; x <= hh; x++) {
				d.push(++r, i + 1);
				for (auto k : anti[i]) {
					d.push(r, k*(high - low + 1) + x - low + row * col + 1);
				}
				mrow[r] = i;
			}
		}

		vector<int> ans = d.getAnyAns();
		for (auto rowId : ans) {
			int id = mrow[rowId];
			grid[id] += type[id] ? 0 : low;
			while (id == mrow[rowId - 1])rowId--, grid[id]++;
		}
		return grid;
	}
private:
	int row, col;//网格行列数
	int low, high;//每个格子填入数字的范围是[low,high],  限制一:low>0
	vector<int>type;//标识所有格子类型,0是需要填数字,1是已知数字,-1是无效格子
	vector<int>grid;//所有格子中的数字
	vector<vector<int>>gridGroup;//每一组有哪些格子
	vector<vector<int>>anti;//每个格子属于哪些组
	int maxNum = 1;
};
string Sudoku(string s, char cEmpty = '.')
{
	vector<vector<int>>gridGroup;
	vector<int>v;
	for (int i = 0; i < 9; i++) {
		v.clear();
		for (int j = 0; j < 9; j++)v.push_back(i * 9 + j);
		gridGroup.push_back(v);
		v.clear();
		for (int j = 0; j < 9; j++)v.push_back(j * 9 + i);
		gridGroup.push_back(v);
	}
	for (int i = 0; i < 3; i++)for (int j = 0; j < 3; j++) {
		v.clear();
		for (int r = i * 3; r < i * 3 + 3; r++)for (int c = j * 3; c < j * 3 + 3; c++)v.push_back(r * 9 + c);
		gridGroup.push_back(v);
	}
	SearchWithGroupSum opt(gridGroup, 9, 9, 1, 9);
	vector<int>grid(81);
	vector<int>type(81);
	for (int i = 0; i < 81; i++)if (s[i] != cEmpty)grid[i] = s[i] - '0', type[i] = 1;
	opt.setGrid(grid);
	opt.setType(type);
	v = opt.getAnyAns();
	string ans(81, '0');
	for (int i = 0; i < 81; i++)ans[i] = v[i] + '0';
	return ans;
}

bool testDancingLink()
{
	string s1 = "......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.";
	string s2 = "416837529982465371735129468571298643293746185864351297647913852359682714128574936";
	EXPECT_EQ(Sudoku(s1), s2);
	return true;
}
bool testCovering()
{
	vector<UndirectedEdge<int>>v;
	v.push_back(vector<int>{0, 1});
	v.push_back(vector<int>{0, 9});
	v.push_back(vector<int>{1, 2});
	v.push_back(vector<int>{2, 3});
	v.push_back(vector<int>{3, 4});
	v.push_back(vector<int>{4, 5});
	v.push_back(vector<int>{5, 6});
	v.push_back(vector<int>{6, 7});
	v.push_back(vector<int>{1, 8});
	v.push_back(vector<int>{6, 8});
	v.push_back(vector<int>{5, 8});
	v.push_back(vector<int>{1, 6});
	v.push_back(vector<int>{2, 6});
	v.push_back(vector<int>{1, 3});
	v.push_back(vector<int>{1, 4});
	v.push_back(vector<int>{1, 5});
	v.push_back(vector<int>{2, 4});
	v.push_back(vector<int>{2, 5});
	v.push_back(vector<int>{3, 5});
	auto ans = GetEdgeCover(5, v);
	EXPECT_EQ(int(ans.size()), 6); //共6种方案
	return true;
}
int main()
{
	if (testDancingLink() && testCovering())cout << "test succ!";
	return 0;
}

五,匈牙利算法

1,代码


class Hungarian
{
public:
	//求二分图最大匹配,v是一边的点集,adjaList的每条边都恰好有一个点在v中
	vector<pair<int, int>> maxMatch(const vector<int>&v, const map<int, vector<int>>&adjaList)
	{
		m.clear();
		this->adjaList = adjaList;
		for (auto i : v) {
			visit.clear();
			find(i);
		}
		vector<pair<int, int>>ans; //每个pair的second都在v中
		for (auto mi : m)ans.push_back(mi);
		return ans;
	}
private:
	bool find(int i)
	{
		for (auto j : adjaList[i]) {
			if (visit[j])continue;
			visit[j] = true;
			if (m.find(j) == m.end() || find(m[j])) {
				m[j] = i;
				return true;
			}
		}
		return false;;
	}
private:
	map<int, int>m;
	map<int, int>visit;
	map<int, vector<int>>adjaList;
};

2,测试代码

template<typename T>
static bool IsSame(const T &a, const T &b)
{
	return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() - v2.size())return false;
	for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
	return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T, T2>&p1, const pair<T, T2>&p2)
{
	return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}

#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}

bool testHungarian()
{
	vector<int>v{ 1,2,3,4 };
	map<int, vector<int>>adja;
	adja[1] = { 5,7 };
	adja[2] = { 5 };
	adja[3] = { 5,6 };
	adja[4] = { 7,8 };
	adja[5] = { 1,2,3 };
	adja[6] = { 3 };
	adja[7] = { 1,4 };
	adja[8] = { 4 };
	auto ans = HungarianMaxMatch(v, adja);
	EXPECT_EQ(int(ans.size()), 4);//{1, 7}, { 2,5 }, { 3,6 }, { 4,8 }
	return true;
}
int main()
{
	if (testHungarian())cout << "test succ!";
	return 0;
}

六,并查集、无向图、最小生成树Kruskal

1,代码


class Union //并查集
{
public:
	Union(int num, bool canZip = true, int startId = 0) //startId一般是0或1,可以大于1,不能太大
	{
		fa.resize(num + startId);
		for (int i = startId; i < fa.size(); i++)fa[i] = i;
		this->canZip = canZip;
		this->startId = startId;
	}
	virtual int find(int x)	//找祖先,canZip控制能否做路径压缩加速
	{
		if (canZip) {
			if (fa[x] == x)return x;
			return fa[x] = find(fa[x]);
		}
		int r = x;
		while (fa[r] != r)r = fa[r];
		return r;
	}
	bool inSame(int x, int y)//是否位于同一个集合
	{
		return find(x) == find(y);
	}
	void merge(int x, int y)//合并2个集合,如果是同一个集合则不做操作
	{
		if (!inSame(x, y))fa[find(x)] = y;
	}
	vector<int> getRoots()//获取所有根节点
	{
		vector<int>ans;
		ans.reserve(fa.size());
		for (int i = startId; i < fa.size(); i++)if (fa[i] == i)ans.push_back(i);
		return ans;
	}
	int getRootNums()//统计根节点数目
	{
		return getRoots().size();
	}
	vector<vector<int>> getGroups()
	{
		vector<int> roots = getRoots();
		map<int, int>m = reflect(roots);
		vector<vector<int>>ans(m.size());
		for (int i = startId; i < fa.size(); i++)ans[m[find(i)]].push_back(i);
		return ans;
	}
protected:
	template<typename T>
	map<T, int> reflect(const vector<T>& v)
	{
		map<T, int>m;
		for (int i = 0; i < v.size(); i++)m[v[i]] = i;
		return m;
	}
protected:
	vector<int>fa;
	bool canZip;
	int startId;
};
class UnionDif :public Union //差分版并查集,依赖路径压缩
{
public:
	UnionDif(int num, int startId = 0) :Union{ num,true,startId } {}
	int find(int x)	//找祖先
	{
		if (fa[x] == x)return x;
		find(fa[x]);
		dif[x] += dif[fa[x]];
		fa[x] = fa[fa[x]];
		return fa[x];
	}
	void merge(int x, int y, double xSubY = 0)//合并2个集合,如果是同一个集合则不做操作
	{
		if (inSame(x, y))return;
		find(x);
		dif[fa[x]] = xSubY - dif[x];
		fa[fa[x]] = y;
		return;
	}
	double getDif(int x)
	{
		return dif[x];
	}
private:
	map<int, double>dif;//每个节点和fa的差分
};
template<typename T>
class Vunion:public Union //集合并查集
{
public:
	Vunion(int num) :Union{ num } {};
	void push(vector<vector<T>>&v) {
		map<T, vector<int>>m;
		for (int i = 0; i < v.size(); i++)for (auto x : v[i])m[x].push_back(i);
		for (auto &p : m) {
			for (auto x : p.second)merge(x, p.second[0]);
		}
	}
};


#ifdef LOCAL
#ifndef struct_TreeNode
#define struct_TreeNode
struct TreeNode {
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode() : val(0), left(nullptr), right(nullptr) {}
	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
	TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};
#endif
#endif

#ifndef struct_UndirectedEdge
#define struct_UndirectedEdge
template<typename T = int>
struct UndirectedEdge
{
	UndirectedEdge() {
		a = b = dist = 0;
	};
	UndirectedEdge(const vector<int>&v) {
		a = v[0], b = v[1], dist = 0;
		if (v.size() > 2)dist = v[2];
	}
    bool operator==(const UndirectedEdge&e) const {
		return a == e.a && b == e.b && dist == e.dist;
	}
	int a;//端点a的id
	int b;//端点b的id
	T dist;//ab之间的距离
};
#endif
template<typename T = int>
struct UndirectedGraphData
{
public:
	vector<UndirectedEdge<T>>edges; //边集,无法表示孤立点,一条边只出现一次
	map<pair<int, int>, T>edgeMap; //边集,无法表示孤立点,一条边出现两次
	map<int, vector<int>>adjaList;//邻接表,孤立点也作为key,一条边两个点都出现在对方的邻接表中
public:
	UndirectedGraphData() {
	}
	UndirectedGraphData(const vector<UndirectedEdge<T>>&edges) {
		this->edges = edges;
		adjaList = undirectedEdgeToAdjaList(edges);
		edgeMap = undirectedEdgeToValueMap(edges);
	}
	UndirectedGraphData(vector<vector<int>>& edges) { //仅限没有权值或者权值为整数的图
		transform(edges.begin(), edges.end(), std::back_inserter(this->edges), [](const vector<int>& v) {return UndirectedEdge<int>{v}; });
		adjaList = undirectedEdgeToAdjaList(this->edges);
		edgeMap = undirectedEdgeToValueMap(this->edges);
	}
	UndirectedGraphData(const map<int, vector<int>>& adjaList) { //仅限没有权值的图
		this->adjaList = adjaList;
		for (auto& v : this->adjaList) {
			for (auto vi : v.second)if (v.first < vi)edges.push_back(UndirectedEdge<T>(vector<int>{v.first, vi, 0}));
		}
		edgeMap = undirectedEdgeToValueMap(edges);
	}
	void setNumV(int n = 1, int startId = 0) { //如果用edges初始化对象,但是存在孤立点,则可以调用setNumV
		for (int i = startId; i < startId + n; i++)adjaList[i];
	}
	int getNumV() const {
		return adjaList.size();
	}
	int getNumE() const {
		return edges.size();
	}
private:
	//输入无向边集{{1,2}{1,3}{2,3}},输出邻接表{1:{2,3},2:{1,3},3:{1,2}}
	static map<int, vector<int>> undirectedEdgeToAdjaList(const vector<UndirectedEdge<T>>& v)
	{
		map<int, vector<int>> ans;
		for (auto& vi : v) {
			ans[vi.a].push_back(vi.b);
			ans[vi.b].push_back(vi.a);
		}
		return ans;
	}
	//输入无向带权边集,输出边和权的映射
	static map<pair<int, int>, T> undirectedEdgeToValueMap(const vector<UndirectedEdge<T>>& v)
	{
		map<pair<int, int>, T>m;
		for (auto& vi : v) {
			m[{vi.a, vi.b}] = vi.dist;
			m[{vi.b, vi.a}] = vi.dist;
		}
		return m;
	}
};
class UndirectedGraph
{
public:
	//输入二叉树,转化成无向图的邻接表,没有权值, 节点编号是先序遍历的编号,默认从0开始
	static map<int, vector<int>> getAdjaList(TreeNode* root, int startId = 0)
	{
		map<int, vector<int>> m;
		if (root)getAdjaList(root, m, startId);
		return m;
	}
	//输入无环无向图,生成任意一棵二叉树,val存放原id,节点编号是从0开始依次编号
	static TreeNode* edgesToBinaryTree(const UndirectedGraphData<int> &g)
	{
		map<int, int>ids;
		for (auto &e : g.edges) {
			if (ids.find(e.a) == ids.end())ids[e.a] = ids.size();
			if (ids.find(e.b) == ids.end())ids[e.b] = ids.size();
		}
		map<int, vector<int>>m = g.adjaList;
		Union un(ids.size());
		for (auto &e : g.edges) {
			int id0 = ids[e.a], id1 = ids[e.b];
			if (!un.inSame(id0, id1)) {
				un.merge(id0, id1);
			}
		}
		int id = -12345;
		for (auto &mi : m)if (mi.second.size() < 3) {
			id = mi.first;
			break;
		}
		if (id == -12345)return nullptr;
		map<int, int>visit;
		TreeNode* ans = new TreeNode(id);
		queue<TreeNode*>q;
		q.push(ans);
		while (!q.empty()) {
			TreeNode* p = q.front();
			q.pop();
			visit[p->val] = 1;
			for (auto x : m[p->val])if (visit[x] == 0) {
				TreeNode* p2 = new TreeNode(x);
				q.push(p2);
				if (!p->left)p->left = p2;
				else p->right = p2;
			}
		}
		return ans;
	}
	//无向拓扑排序,输入无向无环图{{1,2}{1,3}{4,3}}和指定根1,输出父节点表{4:3, 3:1, 2:1}
	static map<int, int> undirectedEdgeToFatherList(UndirectedGraphData<int> &g, int root)
	{
		auto& m = g.adjaList;
		map<int, int>visit;
		map<int, int>fa;
		queue<int>q;
		q.push(root);
		visit[root] = 1;
		while (!q.empty()) {
			int id = q.front();
			q.pop();
			for (auto c : m[id]) {
				if (visit[c] == 0)q.push(c), fa[c] = id;
				visit[c] = 1;
			}
		}
		return fa;
	}
	//判断无向图是否有环
	static bool hasUndirectedCircle(const UndirectedGraphData<int>& g)
	{
		auto& m = g.adjaList;
		vector<int>keys; //auto keys = getFirst(m);
		transform(m.begin(), m.end(), std::back_inserter(keys), [](const pair<int, vector<int>>& p) {return p.first; });
		int minkey = *min_element(keys.begin(), keys.end());
		int maxKey = *max_element(keys.begin(), keys.end());
		Union unions(maxKey - minkey + 1);
		map<pair<int, int>, int>mp;
		for (auto& mi : m) {
			for (auto k : mi.second) {
				if (mp[make_pair(k, mi.first)])continue;
				if (unions.inSame(k - minkey, mi.first - minkey))return true;
				unions.merge(k - minkey, mi.first - minkey);
				mp[make_pair(mi.first, k)] = 1;
			}
		}
		return false;
	}
	//判断是不是k-正则图
	static bool isCompleteGraph(int k, const UndirectedGraphData<int> &g)
	{
		for (auto &mi : g.adjaList) {
			if (mi.second.size() != k)return false;
		}
		return true;
	}
	//判断是不是二分图, 节点编号都在[0,n)区间内
	static bool isTwoDivGraph(int n, const UndirectedGraphData<int> &g) {
		UnionDif unions(n);
		for (auto e : g.edges) {
			unions.find(e.a);
			unions.find(e.b);
			if (unions.inSame(e.a, e.b)) {
				if (int(unions.getDif(e.a) + unions.getDif(e.b)) % 2 == 0)return false;
			}
			else {
				unions.merge(e.a, e.b, 1);
			}
		}
		return true;
	}
private:
	static void getAdjaList(TreeNode* root, map<int, vector<int>>& adjaList, int &id)
	{
		int rid = id;
		if (root->left) {
			++id;
			adjaList[rid].push_back(id);
			adjaList[id].push_back(rid);
			getAdjaList(root->left, adjaList, id);
		}
		if (root->right) {
			++id;
			adjaList[rid].push_back(id);
			adjaList[id].push_back(rid);
			getAdjaList(root->right, adjaList, id);
		}
	}
};

class Kruskal
{
public:
	//计算最小生成树,结果按照边从小到大排序,出参treeNum是森林中树的数量
	static vector<UndirectedEdge<int>> kruskalMinCostTree(int n, vector<UndirectedEdge<int>>& v, int& treeNum)
	{
		sort(v.begin(), v.end(), cmp);
		Union unions(n);
		vector<UndirectedEdge<int>>ans;
		for (int i = 0, j = 0; j < n - 1 && i < v.size(); i++)
		{
			if (unions.inSame(v[i].a, v[i].b))continue;
			unions.merge(v[i].a, v[i].b);
			ans.push_back(v[i]);
			j++;
		}
		treeNum = unions.getRootNums();
		return ans;
	}
private:
	static bool cmp(UndirectedEdge<int>& a, UndirectedEdge<int>& b)
	{
		return a.dist < b.dist;
	}
};

2,测试代码

template<typename T>
static bool IsSame(const T &a, const T &b)
{
	return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() - v2.size())return false;
	for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
	return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T, T2>&p1, const pair<T, T2>&p2)
{
	return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}
template<typename T, typename T2>
static bool IsSame(const map<T, T2>&m1, const map<T, T2>&m2)
{
	if (m1.size() - m2.size())return false;
	for (auto mi : m1) {
		auto it = m2.find(mi.first);
		if (it == m2.end())return false;
		if (!IsSame(mi.second, it->second))return false;
	}
	return true;
}

#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}

bool testUnion()
{
	Union un(10);// {0,3,4,7},{1,2},{5,6,8,9}
	un.merge(0, 3);
	un.merge(1, 2);
	un.merge(4, 7);
	un.merge(4, 3);
	un.merge(5, 5);
	un.merge(5, 6);
	un.merge(5, 8);
	un.merge(5, 9);
	un.merge(9, 8);
	EXPECT_EQ(un.getRootNums(), 3);
	return true;
}
bool testUndirectedGraph1()
{
	TreeNode* root = new TreeNode(3);
	root->left = new TreeNode(4);
	root->right = new TreeNode(6);
	root->left->left = new TreeNode(7);
	root->left->right = new TreeNode(8);
	root->right->right = new TreeNode(9);
	root->right->right->left = new TreeNode(11);
	// 3
	//    4
	//        7
	//        8
	//    6
	//        9
	//             11
	map<int, vector<int>> m = GetAdjaListFromTree(root);
	// 0
	//    1
	//        2
	//        3
	//    4
	//        5
	//             6
	map<int, vector<int>> m2;
	m2[0] = { 1,4 };
	m2[1] = { 0,2,3 };
	m2[2] = { 1 };
	m2[3] = { 1 };
	m2[4] = { 0,5 };
	m2[5] = { 4,6 };
	m2[6] = { 5 };
	for (int i = 0; i <= 6; i++) {
		auto v1 = m[i], v2 = m2[i];
		sort(v1.begin(), v1.end());
		EXPECT_EQ(v1, v2);
	}
	UndirectedGraphData<int>g(m);
	TreeNode* r = EdgesToBinaryTree(g);
	map<int, vector<int>> m3 = GetAdjaListFromTree(r);
	for (int i = 0; i <= 6; i++) {
		auto v1 = m3[i], v2 = m2[i];
		sort(v1.begin(), v1.end());
		EXPECT_EQ(v1, v2);
	}
	return true;
}
bool testUndirectedGraph2()
{
	map<int, vector<int>> m; //无向无环图{{1,2}{1,3}{4,3}}
	m[1] = { 2,3 };
	m[2] = { 1 };
	m[3] = { 1,4 };
	m[4] = { 3 };
	UndirectedGraphData<int>g(m);
	map<int, int> mFa = UndirectedEdgeToFatherList(g, 1);
	map<int, int> mFa2; //父节点表{4:3, 3:1, 2:1}
	mFa2[4] = 3;
	mFa2[3] = 1;
	mFa2[2] = 1;
	EXPECT_EQ(mFa, mFa2);
	EXPECT_EQ(HasUndirectedCircle(m), false);
	EXPECT_EQ(IsTwoDivGraph(10, m), true);
	m[2].push_back(3);
	m[3].push_back(2);
	EXPECT_EQ(HasUndirectedCircle(m), true);
	EXPECT_EQ(IsTwoDivGraph(10, m), false);
	EXPECT_EQ(IsCompleteGraph(3,m), false);
	m[2].push_back(4);
	m[4].push_back(2);
	m[1].push_back(4);
	m[4].push_back(1);
	EXPECT_EQ(IsCompleteGraph(3, m), true);
	return true;
}
bool testKruskal()
{
	vector<vector<int>>v{
		{1,2,1},
		{2,3,2},
		{3,4,1},
		{4,1,2}, //id=3
		{5,6,3},
		{6,7,4},
		{7,8,5},
		{8,5,6} //id=7
	};
	UndirectedGraphData<int>g(v);
	vector<UndirectedEdge<int>>e = g.edges;
	int trreNum;
	vector<UndirectedEdge<int>> ans = KruskalMinCostTree(9, e, trreNum);
	EXPECT_EQ(trreNum, 3);
	e.erase(e.begin() + 7);
	e.erase(e.begin() + 3);
	EXPECT_EQ(e, ans);
	return true;
}
int main()
{
	if (testUnion() && testUndirectedGraph1() && testUndirectedGraph2() && testKruskal())cout << "test succ!";
	return 0;
}

七,最小生成树Prim

1,代码


class Prim
{
public:
	//输入边集,计算最小生成树,输出的每条边是往外扩散的方向
	//即使输入的value只有{1,2}这条边,没有{2,1}这条边,输出的边集也可能有{2,1}
	static vector<pair<int, int>> minCostConnectPoints(int n, map<pair<int, int>, int> value)//value慎用引用
	{
		doubleEdge(value);
		vector<bool>visit_(n);
		vector<int>minLen(n);
		for (int i = 0; i < n; i++) {
			minLen[i] = INT_MAX;
			visit_[i] = false;
		}
		int startId = getStartId(n, value);
		minLen[startId] = 0;
		vector<pair<int, int>>ans;
		for (int i = 0; i < n; i++) {
			int id = getId(n, visit_, minLen);
			for (int j = 0; j < n; j++) {
				if (visit_[j] && value[make_pair(j, id)] == minLen[id]) {
					ans.push_back(make_pair(j,id));
					break;
				}
			}
			visit_[id] = true;
			fresh(n, visit_, minLen, value, id);
		}
		return ans;
	}
private:
	static void doubleEdge(map<pair<int, int>, int>& value)
	{
		set<pair<int, int>>s;
		for (auto mi : value)s.insert(mi.first);
		for (auto p : s) {
			value[{p.second, p.first}] = value[p];
		}
	}
	static int getStartId(int n, map<pair<int, int>, int>& value)
	{
		int m = INT_MAX;
		int ans = 0;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				if (i == j)continue;
				auto p = make_pair(i, j);
				auto it = value.find(p);
				if (it != value.end() && m > it->second) {
					m = it->second;
					ans = i;
				}
			}
		}
		return ans;
	}
	static int getId(int n, vector<bool>& visit_, vector<int>& minLen)
	{
		int m = INT_MAX;
		int ans = 0;
		for (int i = 0; i < n; i++) {
			if (!visit_[i] && m > minLen[i]) {
				m = minLen[i];
				ans = i;
			}
		}
		return ans;
	}
	static void fresh(int n, vector<bool>& visit_, vector<int>& minLen, map<pair<int, int>, int>& value, int id)
	{
		for (int i = 0; i < n; i++) {
			auto p = make_pair(i, id);
			if (!visit_[i] && value.find(p)!=value.end())minLen[i] = min(minLen[i], value[p]);
		}
	}
};

2,测试代码


template<typename T>
static bool IsSame(const T &a, const T &b)
{
	return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() - v2.size())return false;
	for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
	return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T, T2>&p1, const pair<T, T2>&p2)
{
	return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}
template<typename T, typename T2>
static bool IsSame(const map<T, T2>&m1, const map<T, T2>&m2)
{
	if (m1.size() - m2.size())return false;
	for (auto mi : m1) {
		auto it = m2.find(mi.first);
		if (it == m2.end())return false;
		if (!IsSame(mi.second, it->second))return false;
	}
	return true;
}

#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}

bool testPrim()
{
	map<pair<int, int>, int>m;	
	m[{1, 2}] = 1;
	m[{2, 3}] = 2;
	m[{3, 4}] = 1;
	m[{1, 4}] = 2;
	m[{5, 6}] = 3;
	m[{6, 7}] = 4;
	m[{7, 8}] = 5;
	m[{5, 8}] = 6;
	m[{0, 1}] = 8;
	m[{0, 8}] = 9;
	vector<pair<int, int>> ans = PrimminCostTree(9, m);
	vector<pair<int, int>> gt{
		{1,2},
		{2,3},
		{3,4},
		{1,0},
		{0,8},
		{8,7},
		{7,6},
		{6,5}
	};
	EXPECT_EQ(ans, gt);
	return true;
}

int main()
{
	if (testPrim())cout << "test succ!";
	return 0;
}

八,有向图、单源最短路径、连通分量、拓扑排序

1,代码

template<typename T = int>
struct DirectedEdge
{
	DirectedEdge() {
		a = b = dist = 0;
	};
	DirectedEdge(const vector<int>& v) {
		a = v[0], b = v[1], dist = 0;
		if (v.size() > 2)dist = v[2];
	}
	int a;//端点a的id
	int b;//端点b的id
	T dist;//从a到b的距离
};
template<typename T = int>
struct DirectedGraphData
{
public:
	vector<DirectedEdge<T>>edges; //边集,无法表示孤立点
	map<pair<int, int>, T>edgeMap; //边集,无法表示孤立点
	map<int, vector<int>>adjaList;//邻接表,孤立点是否出现取决于allPointFlag
	bool allPointFlag = false;//默认邻接表中不含孤立点
	int startId = 0;
public:
    DirectedGraphData(){
	}
	DirectedGraphData(const vector<DirectedEdge<T>>& edges) {
		this->edges = edges;
		adjaList = directedEdgeToAdjaList(edges);
		edgeMap = directedEdgeToValueMap(edges);
	}
	DirectedGraphData(const vector<vector<int>>& edges) { //仅限权值为整数的图
		transform(edges.begin(), edges.end(), std::back_inserter(this->edges), [](const vector<int>& v) {return DirectedEdge<int>{v}; });
		adjaList = directedEdgeToAdjaList(this->edges);
		edgeMap = directedEdgeToValueMap(this->edges);
	}
	DirectedGraphData(map<int, vector<int>>& adjaList) { //仅限没有权值的图
		this->adjaList = adjaList;
		for (auto& v : adjaList) {
			for (auto vi : v.second)edges.push_back(DirectedEdge<T>({v.first, vi, 0}));
		}
		edgeMap = directedEdgeToValueMap(edges);
	}
	void setNumV(int n, int startId = 0) { //startId一般是0或1,可以大于1
		allPointFlag = true;
		for (int i = startId; i < startId + n; i++)adjaList[i];
		this->startId = startId;
	}
	int getNumV() const {
		return adjaList.size();
	}
	int getNumE() const {
		return edges.size();
	}
private:
	//输入有向边集{{1,2}{1,3}{2,3}},输出邻接表{1:{2,3},2:{3}}
	static map<int, vector<int>> directedEdgeToAdjaList(const vector<DirectedEdge<T>>& v)
	{
		map<int, vector<int>> ans;
		for (auto& vi : v) {
			ans[vi.a].push_back(vi.b);
			ans[vi.b];
		}
		return ans;
	}
	//输入有向带权边集,输出边和权的映射
	static map<pair<int, int>, int> directedEdgeToValueMap(const vector<DirectedEdge<T>>& v)
	{
		map<pair<int, int>, int>m;
		for (auto& vi : v) {
			m[{vi.a, vi.b}] = vi.dist;
		}
		return m;
	}
};
class DirectedGraph
{
public:
	//构建有向图的反向图
	static map<int, vector<int>> reverseGraph(const DirectedGraphData<int> &g)
	{
		auto& m = g.adjaList;
		map<int, vector<int>> ans;
		for (auto& mi : m) {
			for (auto& k : mi.second)ans[k].push_back(mi.first);
		}
		return ans;
	}
	//求有向无环图中的最长路径长度,出参nextNode是每个点的后继,len是每个点出发的最长路径长度
	static int getLongestPath(map<int, vector<int>>& m, map<int, int>& nextNode, map<int, int>& len)
	{
		int ans = 0;
		for (auto& ai : m)ans = max(ans, dp(m, nextNode, len, ai.first));
		return ans;
	}
	//判断是否有环
	static bool hasCircle(int numCourses, map<int, vector<int>>& m)
	{
		map<int, int>visitt;//单次访问标记
		map<int, int>flag;//所有访问标记
		for (int i = 0; i < numCourses; i++)
		{
			if (flag[i])continue;
			if (!canFinish(m, i, visitt, flag))return true;
		}
		return false;
	}

private:
	static int dp(map<int, vector<int>>& m, map<int, int>& nextNode, map<int, int>& len, int id)
	{
		if (len[id])return len[id];
		len[id] = 1, nextNode[id] = -1; //无后继的则是 - 1
		for (auto k : m[id]) {
			if (len[id] < dp(m, nextNode, len, k) + 1) {
				len[id] = dp(m, nextNode, len, k) + 1;
				nextNode[id] = k;
			}
		}
		return len[id];
	}
	static bool canFinish(map<int, vector<int>>& m, int loc, map<int, int>& visitt, map<int, int>& flag) {
		if (visitt[loc] == 1)return false;
		if (flag[loc] == 1)return true;
		visitt[loc] = 1, flag[loc] = 1;
		for (int k : m[loc])if (!canFinish(m, k, visitt, flag))return false;
		visitt[loc] = 0;
		return true;
	}
};
class Dijskra//求最短路,适用于不存在负权值的边的图
{
public:
	static map<int, int> shortestPath(map<int, vector<int>>& m, map<pair<int, int>, int>& value, int n, int src)
	{
		map<int, int>dis;
		priority_queue< Node, vector< Node>, cmp>que;
		map<int, int>visit;
		for (int i = 0; i < n; i++)dis[i] = INT_MAX;//节点编号是从0到n-1
		que.push({ src,0 });
		dis[src] = 0;
		while (!que.empty())
		{
			Node nod = que.top();
			que.pop();
			if (visit[nod.id])continue;
			visit[nod.id] = 1;
			for (auto& vi : m[nod.id]) {
				if (nod.len + value[{nod.id, vi}] < dis[vi]) {
					que.push({ vi, dis[vi] = nod.len + value[{nod.id, vi}] });
				}
			}
		}
		return dis;
	}
private:
	struct Node
	{
		int id;
		int len;
	};
	class cmp
	{
	public:
		bool operator()(Node a, Node b)
		{
			return a.len > b.len;
		}
	};
};
class BellmanFord //求最短路,适用于不存在负权值的环的图
{
public:
	static map<int, int> shortestPath(const DirectedGraphData<int>& g, int src)
	{
		map<int, int>dis;
		int n = g.getNumV();
		for (int i = 0; i < n; i++)dis[i] = INT_MAX;
		dis[src] = 0;
		for (int i = 0; i < n; i++) {
			if (!refresh(g.edgeMap, dis))break;
			if (i == n - 1)return map<int, int>{}; //有负环
		}
		return dis;
	}
private:
	static inline bool refresh(const map<pair<int, int>, int>& value, map<int, int>&dis)
	{
		bool flag = false;
		auto dis2 = dis;
		for (auto& e : value) {
			if (dis2[e.first.second] > ((long long)dis[e.first.first]) + e.second) {
				dis2[e.first.second] = ((long long)dis[e.first.first]) + e.second, flag = true;
			}
		}
		dis = dis2;
		return flag;
	}
};
class SPFA //求最短路,适用于不存在负权值的环的图
{
public:
	static map<int, int> shortestPath(const DirectedGraphData<int>& g, int src)
	{
		map<int, int>dis;
		map<int, bool>inQueue;
		map<int, int>visit;
		int n = g.getNumV();
		for (int i = 0; i < n; i++)dis[i] = INT_MAX;
		dis[src] = 0;
		queue<int>q;
		q.push(src);
		visit[src]++;
		inQueue[src] = true;
		while (!q.empty()) {
			int t = q.front();
			q.pop();
			inQueue[t] = false;
			auto v = refresh(dis, t, g);
			for (auto vi : v) {
				if (inQueue[vi])continue;
				q.push(vi);
				inQueue[vi] = true;
				if (++visit[vi] >= n)return map<int, int>{};//存在负环
			}
		}
		return dis;
	}
private:
	static inline vector<int> refresh(map<int, int>&dis, int t, const DirectedGraphData<int>& g)
	{
		vector<int>ans;
		auto it = g.adjaList.find(t);
		if (it == g.adjaList.end())return ans;
		long long d = dis[t];
		for (auto vi : it->second) {
			if (dis[vi] > d + g.edgeMap.at(make_pair(t, vi))) {
				dis[vi] = d + g.edgeMap.at(make_pair(t, vi));
				ans.push_back(vi);
			}
		}
		return ans;
	}
};
//不区分有向图和无向图的通用操作
class GraphOpt
{
public:
	//根据点集取子图,输入邻接表,输出邻接表
	static map<int, vector<int>> getSubGraph(map<int, vector<int>>& m, vector<int>& v)
	{
		map<int, vector<int>>ans;
		map<int, int>mv;
		for (auto vi : v)mv[vi] = 1;
		for (auto vi : v) {
			for (auto mi : m[vi]) {
				if (mv[mi])ans[vi].push_back(mi);
			}
		}
		return ans;
	}
};
class SemiConnect
{
public:
	//半连通分量分割
	static vector<vector<int>> semiConnectComponent(map<int, vector<int>>& m)
	{
		vector<vector<int>>allans;
		map<int, int>visit;
		for (auto& mi : m) {
			int k = mi.first;
			if (visit[k])continue;
			vector<int>ans;
			DFS(m, visit, k, ans);
			allans.push_back(ans);
		}
		return allans;
	}
protected:
	//DFS从k开始遍历,记录所有节点最后一次访问的顺序的反序
	static void DFS(map<int, vector<int>>& m, map<int, int>& visit, int k, vector<int>& ans)
	{
		if (visit[k])return;
		visit[k] = 1;
		for (auto i : m[k])DFS(m, visit, i, ans);
		ans.insert(ans.begin(), k);
	}
};
class KosarajuStrongConnect :public DirectedGraph, public GraphOpt, public SemiConnect
{
public:
	//Kosaraju算法,强连通分量分割
	static vector<vector<int>> connectComponent(map<int, vector<int>>& m)
	{
		vector<vector<int>> semi = semiConnectComponent(m);
		auto m2 = reverseGraph(m);
		vector<vector<int>>allans;
		map<int, int>visit;
		for (auto& s : semi) {
			auto m3 = getSubGraph(m2, s);
			for (auto& k : s) {
				if (visit[k])continue;
				vector<int>ans;
				DFS(m3, visit, k, ans);
				allans.push_back(ans);
			}
		}
		return allans;
	}
	//强连通分量缩点,输入强连通分量列表,输出缩点后的邻接表
	static map<int, vector<int>> getPointGraph(vector<vector<int>>&v, map<int, vector<int>>&m)
	{
		map<int, int>g;
		map<int, vector<int>>ans;
		for (int i = 0; i < v.size(); i++)for (auto x : v[i])g[x] = i;
		for (auto &mi : m) {
			for (auto x : mi.second)
				if (g[x] != g[mi.first])
					ans[mi.first].push_back(x);
		}
		return ans;
	}
};
class TarjanDoubledirect
{
public:
	vector<pair<int, int>>cutb;//割边
	vector<int>cutv;//割点
	vector<vector<int>>conv;//点双连通分量的点集
	vector<vector<long long>>convb;//点双连通分量的边集
	int cons = 0;//无向连通分量数目
	TarjanDoubledirect(int n, map<int, vector<int>>& m)
	{
		this->n = n;
		this->m = m;
		visit.resize(n);
		added.resize(n);
		dfn.resize(n);
		low.resize(n);
		for (int i = 0; i < n; i++)if (!visit[i]) {
			root = i;
			dfs(i);
			cons++;
		}
		FillConv();
	}
private:
	void dfs(int k)
	{
		visit[k] = true;
		low[k] = dfn[k] = dfnId++;
		bool cv = false;
		int chNum = 0;
		st.push(k);
		for (auto nk : m[k]) {
			if (isBackB(nk))low[k] = min(low[k], dfn[nk]);
			if (visit[nk])continue;
			chNum++;
			sFa.push(k);
			dfs(nk);
			sFa.pop();
			low[k] = min(low[k], low[nk]);
			vector<int>conv1;
			vector<long long>convb1;
			if (low[nk] >= dfn[k]) {
				cv = true;
				for (int time = INT_MAX; time; time--) {
					if (st.top() == nk)time = 1;
					conv1.push_back(st.top());
					added[st.top()] = true;
					for (auto i : m[st.top()])if (!added[i])convb1.push_back((long long)(st.top()) * n + i);
					st.pop();
				}
				if (conv1.size() > 1) {
					conv1.push_back(k);
					conv.push_back(conv1);
					convb.push_back(convb1);
				}
			}
			if (low[nk] >= dfn[nk])cutb.push_back(make_pair(k, nk));
		}
		if ((k != root && cv && chNum > 0) || (k == root && chNum > 1))cutv.push_back(k);
	}
	bool isBackB(int nk) // 判断从k到nk是不是后向边
	{
		return visit[nk] && (sFa.empty() || nk != sFa.top());//如果st.top()是nk,则是树边,不是后向边
	}
	void FillConv()//补充由单点组成的点连通分量
	{
		map<int, int>m;
		for (auto& ci : conv) {
			for (auto& k : ci)m[k] = 1;
		}
		vector<int>conv1(1);
		for (int i = 0; i < n; i++)if (m[i] == 0) {
			conv1[0] = i;
			conv.push_back(conv1);
			convb.push_back(vector<long long>());
		}
	}
	int n;
	int dfnId = 0;
	int root;
	vector<bool>visit;//DFS访问标记
	vector<bool>added;
	vector<int>dfn;//首次访问的次序
	vector<int>low;//通过一条后向边能达到的最小dfn
	map<int, vector<int>> m;//邻接表
	stack<int>sFa;//用于判断父节点
	stack<int>st;
};
class TarjanStrongConnect
{
public:
	vector<vector<int>>conv;//强连通分量的点集
	TarjanStrongConnect(int n, map<int, vector<int>>& m)
	{
		this->n = n;
		this->m = m;
		visit.resize(n);
		added.resize(n);
		dfn.resize(n);
		low.resize(n);
		for (int i = 0; i < n; i++)if (!visit[i]) {
			root = i;
			dfs(i);
		}
		FillConv();
	}
private:
	void dfs(int k)
	{
		visit[k] = true;
		low[k] = dfn[k] = dfnId++;
		bool cv = false;
		int chNum = 0;
		st.push(k);
		for (auto nk : m[k]) {
			if (isBackB(nk))low[k] = min(low[k], dfn[nk]);
			if (visit[nk])continue;
			chNum++;
			dfs(nk);
			low[k] = min(low[k], low[nk]);
		}
		vector<int>conv1;
		vector<long long>convb1;
		if (low[k] >= dfn[k]) {
			cv = true;
			for (int time = INT_MAX; time; time--) {
				if (st.top() == k)time = 1;
				conv1.push_back(st.top());
				added[st.top()] = true;
				st.pop();
			}
			conv.push_back(conv1);
		}
	}
	bool isBackB(int nk) // 判断从k到nk是不是后向边
	{
		return visit[nk] && !added[nk];
	}
	void FillConv()//补充由单点组成的点连通分量
	{
		map<int, int>m;
		for (auto& ci : conv) {
			for (auto& k : ci)m[k] = 1;
		}
		vector<int>conv1(1);
		for (int i = 0; i < n; i++)if (m[i] == 0) {
			conv1[0] = i;
			conv.push_back(conv1);
		}
	}
	int n;
	int dfnId = 0;
	int root;
	vector<bool>visit;//DFS访问标记
	vector<bool>added;
	vector<int>dfn;//首次访问的次序
	vector<int>low;//通过一条后向边能达到的最小dfn
	map<int, vector<int>> m;//邻接表
	stack<int>st;
};
//有向图拓扑排序
class DirectedTopoSort:public KosarajuStrongConnect
{
public:
	//有向无环图拓扑排序,输入n=3,g.edges={{0,1}{0,2}{1,2}}, 输出{0,1,2},有环则输出为空
	static vector<int> topoSortNoCircle(int n, DirectedGraphData<int>& g)
	{
		auto& v = g.edges;
		priority_queue<int, vector<int>, greater<int>> q;
		map<int, int>m;
		for (auto &vi : v)m[vi.b]++;
		for (int i = 0; i < n; i++)if (m[i] == 0)q.push(i);
		vector<int>ans;
		auto &mv = g.adjaList;
		while (!q.empty()) {
			int k = q.top();
			q.pop();
			ans.push_back(k);
			for (auto i : mv[k]) {
				m[i]--;
				if (m[i] == 0)q.push(i);
			}
		}
		return ans.size() == n ? ans : vector<int>{};
	}
	//有向图拓扑排序
	static vector<vector<int>> topoSort(DirectedGraphData<int>& g)
	{
		vector<vector<int>> con = connectComponent(g.adjaList);
		map<int, vector<int>> pointGraph = getPointGraph(con, g.adjaList);
		DirectedGraphData<int>ga(pointGraph);
		vector<int> vp = topoSortNoCircle(con.size(), ga);
		vector<vector<int>>ans;
		for (auto id : vp)ans.push_back(con[id]);
		return ans;
	}
};

2,测试代码

bool testDirectedGraph()//待完善
{
	DirectedGraph{};
	return true;
}
bool testDijskra()//待完善
{
	map<int, vector<int>> m;
	map<pair<int, int>, int> value;
	int n = 1;
	DijskraShortestPath(m, value, n, 0);
	return true;
}
bool testBellmanFord()//待完善
{
	return true;
}
bool testGraphOpt()//待完善
{
	GraphOpt{};
	return true;
}
bool testConnect()//待完善
{
	SemiConnect{};
	KosarajuStrongConnect{};
	int n = 1;
	map<int, vector<int>> m;
	TarjanDoubledirect{ n,m };
	TarjanStrongConnect{ n,m };
	return true;
}
bool testTopoSort() //待完善
{
	map<int, vector<int>>m;
	m[1].push_back(2);
	m[2].push_back(3);
	m[3].push_back(1);
	m[3].push_back(4);
	m[4].push_back(5);
	m[5].push_back(6);
	m[6].push_back(4);
	m[5].push_back(7);
	DirectedGraphData<int>g(m);
	auto ans = DirectedTopoSort::topoSort(g);
	return true;
}
bool test5()
{
	return testDirectedGraph() && testDijskra() && testBellmanFord() && testGraphOpt() && testConnect() && testTopoSort();
}

int main()
{
	if (test5())cout << "test succ!";
	return 0;
}

九,网格图、回路链路、路径重建

1,代码

class GridGraph
{
public:
	GridGraph(int row, int col)
	{
		this->row = row;
		this->col = col;
		initD4D8();
	}
	int gridId(int r, int c) //阅读顺序的id,先给col赋值再调用
	{
		return r * col + c;
	}
	vector<int> getNeighbor4(int k)//获得四邻居的id
	{
		vector<int>ans;
		for (int i = 0; i < 4; i++) {
			if (inBoard(k / col + dx4[i], k % col + dy4[i]))ans.push_back(k + d4[i]);
		}
		return ans;
	}
	vector<int> getNeighbor8(int k)//获得八邻居的id
	{
		vector<int>ans;
		for (int i = 0; i < 8; i++) {
			if (inBoard(k / col + dx8[i], k % col + dy8[i]))ans.push_back(k + d8[i]);
		}
		return ans;
	}
private:
	int row;
	int col;
	//二维坐标系的邻居偏移量
	const vector<int> dx4{ 0,0,1,-1 };
	const vector<int> dy4{ 1,-1,0,0 };
	const vector<int> dx8{ 0,0,1,-1,1,1,-1,-1 };
	const vector<int> dy8{ 1,-1,0,0 ,1,-1,1,-1 };
	//一维id坐标系的邻居偏移量
	vector<int> d4;
	vector<int> d8;
private:
	inline void initD4D8()
	{
		for (int i = 0; i < 4; i++)d4.push_back(gridId(dx4[i], dy4[i]));
		for (int i = 0; i < 8; i++)d8.push_back(gridId(dx8[i], dy8[i]));
	}
	inline bool inBoard(int r, int c)
	{
		return r >= 0 && r < row&& c >= 0 && c < col;
	}
	inline bool inBoard(int id)
	{
		return id >= 0 && inBoard(id / col, id % col);
	}
};
class Hierholzer {
public:
	stack<int>euler;//欧拉回路或链路,栈顶是起点
	Hierholzer(int n, map<int, vector<int>>& m, int type, int start = 0)//type=0是无向图 1是有向图
	{
		this->n = n;
		this->m = m;
		this->type = type;
		dfs(GetStartPoint(start));
	}
private:
	int GetStartPoint(int start)//链路是唯一起点,回路是指定起点
	{
		if (type == 0) {
			for (auto& mi : m) {
				if (mi.second.size() % 2)return mi.first;
				for (auto nk : mi.second)num[id(mi.first, nk)]++;
			}
			for (auto& ni : num)ni.second /= 2;
		}
		else {
			map<int, int>m2;
			for (auto& mi : m)for (auto nk : mi.second)m2[nk]++, num[id(mi.first, nk)]++;
			for (auto& mi : m)if (mi.second.size() > m2[mi.first])return mi.first;
		}
		return start;
	}
	void dfs(int k)
	{
		while (true) {
			while (mid[k] < m[k].size()) {
				if (num[id(k, m[k][mid[k]])]-- <= 0)mid[k]++;
				else sdfs.push(k), k = m[k][mid[k]];
			}
			euler.push(k);
			if (sdfs.empty()) return;
			k = sdfs.top(), sdfs.pop();
		}
	}
	inline long long id(int a, int b)
	{
		if (type == 0 && a > b)a ^= b ^= a ^= b;
		return (long long)a * n + b;
	}
	int n;
	int type;
	stack<int>sdfs;
	map<int, vector<int>> m;//邻接表
	map<int, int>mid;
	map<long long, int>num;//支持多重边
};
class Hamilton
{
public:
	stack<int> hami;//哈密顿链路
	Hamilton(int n, map<int, vector<int>>& m, int type)//type=0是无向图 1是有向图
	{
		this->n = n;
		this->m = m;
		this->type = type;
		for (int i = 0; i < n; i++)dfs(i);
	}
private:
	bool dfs(int k)
	{
		s.push(k);
		if (s.size() == n) {
			hami = s;
			return true;
		}
		for (auto nk : m[k]) {
			if (visit[k])continue;
			visit[k] = 1;
			if (dfs(nk))return true;
			visit[k] = 0;
		}
		s.pop();
		return false;
	}
	int n;
	int type;
	map<int, vector<int>> m;//邻接表
	map<int, int>visit;
	stack<int>s;
};
class ReBuild
{
public:
	stack<int> ans;
	ReBuild(map<int, int>& dis, map<int, vector<int>>& m, int col, int s, int e)
	{
		this->e = e;
		this->col = col;
		ans.push(e);
		dfs(dis, m, s);
	}
private:
	bool dfs(map<int, int>& dis, map<int, vector<int>>& m, int k)
	{
		if (k == e)return true;
		for (int nex : m[k]) {
			if (dis[nex] == dis[k] + len(k, nex) && dfs(dis, m, nex)) {
				ans.push(k);
				return true;
			}
		}
		return false;
	}
	int len(int s, int e)
	{
		if (s / col == e / col)return abs(s - e);
		return abs(s - e) / col;
	}
	int col;
	int e;
};

2,测试代码

bool testGridGraph()//待完善
{
	GridGraph{ 0, 0 };
	return true;
}

bool testHierholzerAndHamilton()//待完善
{
	map<int, vector<int>> m;
	map<pair<int, int>, int> value;
	int n = 1;
	Hierholzer{ n,m,0,0 };
	Hamilton{ n,m,0 };
	return true;
}
bool testReBuild()//待完善
{
	map<int, vector<int>> m;
	map<int, int> dis;
	ReBuild{ dis,m,0,0,0 };
	return true;
}
bool test6()
{
	return testGridGraph() && testHierholzerAndHamilton() && testReBuild();
}

int main()
{
	if (test6())cout << "test succ!";
	return 0;
}

1 论 3 1.1 术语 3 1.2 独立集、覆盖集、支配集之间关系 3 1.3 DFS 4 1.3.1 割顶 6 1.3.2 桥 7 1.3.3 强连通分量 7 1.4 最小点基 7 1.5 拓扑排序 7 1.6 欧拉路 8 1.7 哈密顿路(正确?) 9 1.8 Bellman-ford 9 1.9 差分约束系统(用bellman-ford解) 10 1.10 dag最短路径 10 1.11 匹配 11 1.11.1 匈牙利算法 11 1.11.2 KM算法 12 1.12 网络流 15 1.12.1 最大流 15 1.12.2 上下界的网络的最大流 17 1.12.3 上下界的网络的最小流 17 1.12.4 最小费用最大流 18 1.12.5 上下界的网络的最小费用最小流 21 2 数论 21 2.1 最大公约数gcd 21 2.2 最小公倍数lcm 22 2.3 快速幂取模B^LmodP(O(logb)) 22 2.4 Fermat小定理 22 2.5 Rabin-Miller伪素数测试 22 2.6 Pollard-rho 22 2.7 扩展欧几里德算法extended-gcd 24 2.8 欧拉定理 24 2.9 线性同余方程ax≡b(mod n) 24 2.10 中国剩余定理 25 2.11 Discrete Logging(BL == N (mod P)) 26 2.12 N!最后一个不为0的数字 27 2.13 2^14以内的素数 27 3 数据结构 31 3.1 堆(最小堆) 31 3.1.1 删除最小值元素: 31 3.1.2 插入元素和向上调整: 32 3.1.3 堆的建立 32 3.2 并查集 32 3.3 状数组 33 3.3.1 LOWBIT 33 3.3.2 修改a[p] 33 3.3.3 前缀和A[1]+…+A[p] 34 3.3.4 一个状数组的程序 34 3.4 线段 35 3.5 字符串 38 3.5.1 字符串哈希 38 3.5.2 KMP算法 40 4 计算几何 41 4.1 直线交点 41 4.2 判断线段相交 41 4.3 三点外接圆圆心 42 4.4 判断点在多边形内 43 4.5 两圆交面积 43 4.6 最小包围圆 44 4.7 经纬度坐标 46 4.8 凸包 46 5 Problem 48 5.1 RMQ-LCA 48 5.1.1 Range Minimum Query(RMQ) 49 5.1.2 Lowest Common Ancestor (LCA) 53 5.1.3 Reduction from LCA to RMQ 56 5.1.4 From RMQ to LCA 57 5.1.5 An<O(N), O(1)> algorithm for the restricted RMQ 60 5.1.6 An AC programme 61 5.2 最长公共子序列LCS 64 5.3 最长上升子序列/最长不下降子序列(LIS) 65 5.3.1 O(n^2) 65 5.3.2 O(nlogn) 66 5.4 Joseph问题 67 5.5 0/1背包问题 68 6 组合数学相关 69 6.1 The Number of the Same BST 69 6.2 排列生成 71 6.3 逆序 72 6.3.1 归并排序求逆序 72 7 数值分析 72 7.1 分法 72 7.2 迭代法(x=f(x)) 73 7.3 牛顿迭代 74 7.4 数值积分 74 7.5 高斯消元 75 8 其它 77
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值