目录
类里面和宏定义处都有接口注释,因为宏不体现具体参数,所以注释以类里面的为准。
代码工程结构:



宏定义代码:
-
- #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 EdgesToMultiTree MultiTree::edgesToMultiTree//输入无向图,构造多叉生成树
- // TreeWithId 略。//把二叉树或多叉树转成id形式的树,前序遍历,从0开始编号
- // RMQ 略。
- // LCA 略。
-
- ///(4)DancingLink、Covering///
- // DancingLink 略。精确覆盖算法
- #define GetEdgeCover Covering::getEdgeCover//给定一个2n个点的图,选出n条边,刚好覆盖这2n个点
-
- ///(5.1)并查集///
- // Union 略。并查集
- // UnionDif 略。
- // Vunion 略。
-
- ///(5.2)无向图///
- #define EdgesToBinaryTree UndirectedGraph::edgesToBinaryTree//输入二叉树的边集,生成任意一棵二叉树
- #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//判断是不是二分图
-
- ///(5.3)最小生成树Kruskal///
- #define KruskalMinCostTree Kruskal::kruskalMinCostTree
-
- ///(6)最小生成树Prim///
- #define PrimminCostTree Prim::minCostConnectPoints
-
-
- ///(7.1)有向图///
- #define ReverseGraph DirectedGraph::reverseGraph//构建有向图的反向图
- #define GetLongestPath DirectedGraph::getLongestPath//求有向无环图中的最长路径长度,出参nextNode是每个点的后继,len是每个点出发的最长路径长度
- #define HasDirectedCircle DirectedGraph::hasCircle//根据有向图的邻接表判断是否有环
-
- ///(7.2)单源最短路径///
- #define DijskraShortestPath Dijskra::shortestPath//求最短路,适用于不存在负权值的边的图
- #define BellmanFordShortestPath BellmanFord::shortestPath//求最短路,适用于不存在负权值的环的图
- #define SPFAShortestPath SPFA::shortestPath//求最短路,适用于不存在负权值的环的图
-
- ///(7.3)不区分有向图和无向图的通用操作///
- #define GetSubGraph GraphOpt::getSubGraph//根据点集取子图
-
- ///(7.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 //有向图拓扑排序
-
-
- ///(8.1)网格图///
- // GridGraph 略
-
- ///(8.2)回路或链路///
- // Hierholzer 略。欧拉回路或链路
- // Hamilton 略。哈密顿回路或链路
-
- ///(8.3)路径重建///
- // ReBuild 略。路径重建
-
- #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
int>> levelOrderTraversal(TreeNode* root) { - vector
int>>ans; - if (!root)return ans;
- vector
>v; - vector
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
>&v) { - vector
v1 = *(v.end() - 1); - vector
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;
- }
- };
- template<typename T>
- static bool vecIsSame(const vector
& v1, const vector& v2) - {
- if (v1.size() - v2.size())return false;
- for (int i = 0; i < v1.size(); i++)if (v1[i] != v2[i])return false;
- return true;
- }
- #define EXPECT_VEC_EQ(a,b) if(!vecIsSame((a),(b))){cout<<"ERROR!!!!!!!!!\n";return false;}
- #define EXPECT_EQ(a,b) if(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_VEC_EQ(PreorderTraversal(p), pre);
- EXPECT_VEC_EQ(PostorderTraversal(p), post);
- EXPECT_VEC_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;
- }
-
- 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
- {
- using BASE = SegmentTreeBase
; - 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];
- };
-
- #define EXPECT_EQ(a,b) if(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;
- }
- bool test2()
- {
- return testTreeArray() && testSegmentTree();
- }
-
- int main()
- {
- if (test2())cout << "test succ!";
- return 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
-
- struct MultiTreeNode {
- int val = 0;
- vector
son{}; //son只存实际有的孩子,son可能为空 - MultiTreeNode() {}
- MultiTreeNode(int x) : val(x) {}
- };
-
- class MultiTree {
- public:
- //输入连通的无向图的邻接表,构造一棵多叉生成树,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
int>m;//原指针对应在新树中的编号 - unordered_map
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]);
- }
- };
-
-
- //type=1是求最小值,=2是求最大值, =3是minId,=4是maxId
- template<int type, typename T = int>
- class RMQ
- {
- public:
- RMQ() {}
- RMQ(const vector
& data) { - this->data = data;
- len = data.size();
- logLen = getLength(len + 5);
- init(data);
- }
- inline T getMinMax(int low, int high) { //求[low,high]内的最值,0<=low<=high
- if (low == high)return v[low][0];
- int j = getLength(high - low) - 1;
- return opt(v[high + 1 - (1 << j)][j], v[low][j]);
- }
- inline int getMinMaxId(int low, int high) { //求[low,high]内的最值的id,0<=low<=high
- 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
& 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
data; - vector
>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.getMinMaxId(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;
- };
- bool test3() //待完善
- {
- TreeNode* root = new TreeNode(0);
- TreeWithId tree{ root };
- RMQ<1>{};
- LCA lca(tree);
- return true;
- }
-
- int main()
- {
- if (test3())cout << "test succ!";
- return 0;
- }
- 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
int>> getAllAns() - {
- return dfs(false);
- }
- vector<int> getAnyAns()
- {
- auto v = dfs(true);
- if (v.size())return v[0];
- return vector<int>{};
- }
- private:
- vector
int>> dfs(bool onlyOne) - {
- 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];
- }
- int a;//端点a的id
- int b;//端点b的id
- T dist;//ab之间的距离
- };
- #endif
- class Covering {
- public:
- //给定一个2n个点的图,选出n条边,刚好覆盖这2n个点,返回所有的解
- static vector
int>>> getEdgeCover(int n, vectorint>> &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
int>>>ans; - vector
int>> vrow = d.getAllAns(); - for (auto vi : vrow) {
- vector
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;
- }
- };
-
- bool testDancingLink()//待完善
- {
- return true;
- }
- bool testCovering()//待完善
- {
- return true;
- }
- int main()
- {
- if (testDancingLink() && testCovering())cout << "test succ!";
- return 0;
- }
- 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
int>> getGroups() - {
- vector<int> roots = getRoots();
- map<int, int>m = reflect(roots);
- 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
int > reflect(const vector& v) - {
- map
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
>&v) { - map
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];
- }
- int a;//端点a的id
- int b;//端点b的id
- T dist;//ab之间的距离
- };
- #endif
- template<typename T = int>
- struct UndirectedGraphData
- {
- public:
- vector
>edges; //边集,无法表示孤立点,一条边只出现一次 - map
int, int>, T>edgeMap; //边集,无法表示孤立点,一条边出现两次 - map<int, vector<int>>adjaList;//邻接表,孤立点是否出现取决于allPointFlag,一条边两个点都出现在对方的邻接表中
- bool allPointFlag = false;//默认邻接表中不含孤立点
- int startId = 0;
- public:
- UndirectedGraphData() {
- }
- UndirectedGraphData(const vector
>&edges) { - this->edges = edges;
- adjaList = undirectedEdgeToAdjaList(edges);
- edgeMap = undirectedEdgeToValueMap(edges);
- }
- UndirectedGraphData( 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
(vector<int>{v.first, vi, 0})); - }
- edgeMap = undirectedEdgeToValueMap(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:{1,3},3:{1,2}}
- static map<int, vector<int>> undirectedEdgeToAdjaList(const vector
>& 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
int, int>, T> undirectedEdgeToValueMap(const vector>& v) - {
- map
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:
- //输入二叉树的边集,生成任意一棵二叉树,val存放原id
- static TreeNode* edgesToBinaryTree(vector
int >>& edges) - {
- map<int, int>ids;
- for (auto &e : edges) {
- for (int i = 0; i <= 1; i++) {
- if (ids.find(e[i]) == ids.end())ids[e[i]] = ids.size();
- }
- }
- map<int, vector<int>>m;
- Union un(ids.size());
- for (auto &e : edges) {
- int id0 = ids[e[0]], id1 = ids[e[1]];
- if (!un.inSame(id0, id1)) {
- un.merge(id0, id1);
- m[e[0]].push_back(e[1]);
- m[e[1]].push_back(e[0]);
- }
- }
- 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
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
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, UndirectedGraphData<int> &g)
- {
- for (auto &mi : g.adjaList) {
- if (mi.second.size() != k)return false;
- }
- return true;
- }
- //判断是不是二分图, 节点编号是0到n-1
- static bool isTwoDivGraph(int n, 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)return false;
- }
- else {
- unions.merge(e.a, e.b, 1);
- }
- }
- return true;
- }
- };
-
- class Kruskal
- {
- public:
- //计算最小生成树,结果按照边从小到大排序,出参treeNum是森林中树的数量
- static vector
int>> kruskalMinCostTree(int n, vectorint>>& v, int& treeNum) - {
- sort(v.begin(), v.end(), cmp);
- Union unions(n);
- vector
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;
- }
- };
- template<typename T>
- static bool vecIsSame(const vector
& v1, const vector& v2) - {
- if (v1.size() - v2.size())return false;
- for (int i = 0; i < v1.size(); i++)if (v1[i] != v2[i])return false;
- return true;
- }
- #define EXPECT_VEC_EQ(a,b) if(!vecIsSame((a),(b))){cout<<"ERROR!!!!!!!!!\n";return false;}
-
- bool testUnion()
- {
- Union u(5);
- EXPECT_VEC_EQ(u.getRoots(), (vector<int>{0, 1, 2, 3, 4}));
- u.merge(1, 2);
- u.merge(1, 1);
- u.merge(3, 3);
- EXPECT_VEC_EQ(u.getRoots(), (vector<int>{0, 2, 3, 4}));
- u.merge(4, 3);
- auto v = u.getRoots();
- EXPECT_VEC_EQ(u.getRoots(), (vector<int>{0, 2, 3}));
- return true;
- }
- bool testUndirectedGraph()//待完善
- {
- return true;
- }
- bool testKruskal()//待完善
- {
- Kruskal{};
- return true;
- }
- bool test4()
- {
- return testUnion() && testUndirectedGraph() && testKruskal();
- }
-
- int main()
- {
- if (test4())cout << "test succ!";
- return 0;
- }
-
- class Prim
- {
- public:
- //计算最小生成树,结果按照边从小到大排序
- static vector
int, int>> minCostConnectPoints(int n, mapint, int>, int>& value) - {
- vector<bool>visit_(n);
- vector<int>minLen(n);
- for (int i = 0; i < n; i++) {
- minLen[i] = INT_MAX;
- visit_[i] = false;
- }
- minLen[getStartId(n, value)] = INT_MIN;
- vector
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(id, j)] == minLen[id]) {
- ans.push_back(make_pair(id, j));
- break;
- }
- }
- visit_[id] = true;
- fresh(n, visit_, minLen, value, id);
- }
- return ans;
- }
- private:
- static int getStartId(int n, map
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 && m > value[make_pair(i, j)]) {
- m = value[make_pair(i, j)];
- 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
int , int>, int>& value, int id) - {
- for (int i = 0; i < n; i++) {
- if (!visit_[i])minLen[i] = min(minLen[i], value[make_pair(i, id)]);
- }
- }
- };
- bool testPrim()//待完善
- {
- Prim{};
- return true;
- }
-
- int main()
- {
- if (testPrim())cout << "test succ!";
- return 0;
- }
- template<typename T = int>
- struct DirectedEdge
- {
- DirectedEdge() {
- a = b = dist = 0;
- };
- DirectedEdge(const vector<int>&v) {
- a = v[0], b = v[1], dist = v[2];
- }
- int a;//端点a的id
- int b;//端点b的id
- T dist;//从a到b的距离
- };
- template<typename T = int>
- struct DirectedGraphData
- {
- public:
- vector
>edges; //边集,无法表示孤立点 - map
int, int>, T>edgeMap; //边集,无法表示孤立点 - map<int, vector<int>>adjaList;//邻接表,孤立点是否出现取决于allPointFlag
- bool allPointFlag = false;//默认邻接表中不含孤立点
- int startId = 0;
- public:
- DirectedGraphData(){
- }
- DirectedGraphData(const vector
>& edges) { - this->edges = edges;
- adjaList = directedEdgeToAdjaList(edges);
- edgeMap = directedEdgeToValueMap(edges);
- }
- DirectedGraphData(const 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
({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
>& v) - {
- map<int, vector<int>> ans;
- for (auto& vi : v) {
- ans[vi.a].push_back(vi.b);
- ans[vi.b];
- }
- return ans;
- }
- //输入有向带权边集,输出边和权的映射
- static map
int, int>, int> directedEdgeToValueMap(const vector>& v) - {
- map
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
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;
- 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
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
int>> semiConnectComponent(map<int, vector<int>>& m) - {
- 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
int>> connectComponent(map<int, vector<int>>& m) - {
- vector
int>> semi = semiConnectComponent(m); - auto m2 = reverseGraph(m);
- 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
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
int, int>>cutb;//割边 - vector<int>cutv;//割点
- vector
int>>conv;//点双连通分量的点集 - 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
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
int>> topoSort(DirectedGraphData<int>& g) - {
- 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
int>>ans; - for (auto id : vp)ans.push_back(con[id]);
- return ans;
- }
- };
- bool testDirectedGraph()//待完善
- {
- DirectedGraph{};
- return true;
- }
- bool testDijskra()//待完善
- {
- map<int, vector<int>> m;
- map
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;
- }
- 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;
- };
- bool testGridGraph()//待完善
- {
- GridGraph{ 0, 0 };
- return true;
- }
-
- bool testHierholzerAndHamilton()//待完善
- {
- map<int, vector<int>> m;
- map
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;
- }