目录
〇,全文说明、宏定义代码
类里面和宏定义处都有接口注释,因为宏不体现具体参数,所以注释以类里面的为准。
代码工程结构:
- 每一章的第一节《代码》可以独立编译运行(本地要加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;
}