并查集
練習版
class UnionFindSet
{
public:void swap(int* a, int* b){int tmp = *a;*a = *b;*b = tmp;}UnionFindSet(size_t size):_ufs(size,-1){}int UnionFind(int x){}void Union(int x1, int x2){}//長分支改為相同節點int FindRoot(int x){}bool InSet(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}int SetCount(){}
private:std::vector<int> _ufs;
};
class UnionFindSet
{
public:void swap(int* a, int* b){int tmp = *a;*a = *b;*b = tmp;}UnionFindSet(size_t size):_ufs(size,-1){}int UnionFind(int x){int parent = x;while (_ufs[parent] >= 0){parent = _ufs[parent];}return parent;}void Union(int x1, int x2){int root1 = UnionFind(x1);int root2 = UnionFind(x2);/*if (root1 > root2){swap(&root1, &root2);}if (root1 != root2){_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}*/if (abs(_ufs[root1]) < abs(_ufs[root2]))swap(&root1, &root2);_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}//長分支改為相同節點int FindRoot(int x){int root = x;while (_ufs[root] >= 0){root = _ufs[root];}while (_ufs[x] >= 0){int parent = _ufs[x];_ufs[x] = root;x = parent;}return root;}bool InSet(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}int SetCount(){int count = 0;for (int i = 0; i < _ufs.size(); i++){if (_ufs[i] < 0)count++;}return count;}
private:std::vector<int> _ufs;
};
圖
鄰接矩陣
template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
class Graph
{typedef Graph<V, W, MAX_W, Direction> Self;
public:Graph() = default;// 圖的創建// 1、IO輸入 -- 不方便測試,oj中更適合// 2、圖結構關系寫到文件,讀取文件// 3、手動添加邊Graph(const V* a, size_t n)//鄰接矩陣{_vertexs.reserve(n);for (size_t i = 0; i < n; ++i){_vertexs.push_back(a[i]);_indexMap[a[i]] = i;}_matrix.resize(n);for (size_t i = 0; i < _matrix.size(); ++i){_matrix[i].resize(n, MAX_W);}}size_t GetVertexIndex(const V& v){auto it = _indexMap.find(v);if (it != _indexMap.end()){return it->second;}else{//assert(false);throw invalid_argument("頂點不存在");return -1;}}void _AddEdge(size_t srci, size_t dsti, const W& w){_matrix[srci][dsti] = w;// 無向圖if (Direction == false){_matrix[dsti][srci] = w;}}void AddEdge(const V& src, const V& dst, const W& w){size_t srci = GetVertexIndex(src);size_t dsti = GetVertexIndex(dst);_AddEdge(srci, dsti, w);}void Print(){// 頂點for (size_t i = 0; i < _vertexs.size(); ++i){cout << "[" << i << "]" << "->" << _vertexs[i] << endl;}cout << endl;// 矩陣// 橫下標cout << " ";for (size_t i = 0; i < _vertexs.size(); ++i){//cout << i << " ";printf("%4d", i);}cout << endl;for (size_t i = 0; i < _matrix.size(); ++i){cout << i << " "; // 豎下標for (size_t j = 0; j < _matrix[i].size(); ++j){//cout << _matrix[i][j] << " ";if (_matrix[i][j] == MAX_W){//cout << "* ";printf("%4c", '*');}else{//cout << _matrix[i][j] << " ";printf("%4d", _matrix[i][j]);}}cout << endl;}cout << endl;}
};
鄰接矩陣?
template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
class Graph
{typedef Graph<V, W, MAX_W, Direction> Self;
public:Graph() = default;// 圖的創建// 1、IO輸入 -- 不方便測試,oj中更適合// 2、圖結構關系寫到文件,讀取文件// 3、手動添加邊Graph(const V* a, size_t n)//鄰接矩陣{_vertexs.reserve(n);for (size_t i = 0; i < n; ++i){_vertexs.push_back(a[i]);_indexMap[a[i]] = i;}_matrix.resize(n);for (size_t i = 0; i < _matrix.size(); ++i){_matrix[i].resize(n, MAX_W);}}size_t GetVertexIndex(const V& v){auto it = _indexMap.find(v);if (it != _indexMap.end()){return it->second;}else{//assert(false);throw invalid_argument("頂點不存在");return -1;}}void _AddEdge(size_t srci, size_t dsti, const W& w){_matrix[srci][dsti] = w;// 無向圖if (Direction == false){_matrix[dsti][srci] = w;}}void AddEdge(const V& src, const V& dst, const W& w){size_t srci = GetVertexIndex(src);size_t dsti = GetVertexIndex(dst);_AddEdge(srci, dsti, w);}void Print(){// 頂點for (size_t i = 0; i < _vertexs.size(); ++i){cout << "[" << i << "]" << "->" << _vertexs[i] << endl;}cout << endl;// 矩陣// 橫下標cout << " ";for (size_t i = 0; i < _vertexs.size(); ++i){//cout << i << " ";printf("%4d", i);}cout << endl;for (size_t i = 0; i < _matrix.size(); ++i){cout << i << " "; // 豎下標for (size_t j = 0; j < _matrix[i].size(); ++j){//cout << _matrix[i][j] << " ";if (_matrix[i][j] == MAX_W){//cout << "* ";printf("%4c", '*');}else{//cout << _matrix[i][j] << " ";printf("%4d", _matrix[i][j]);}}cout << endl;}cout << endl;}
private:vector<V> _vertexs; // 頂點集合map<V, int> _indexMap; // 頂點映射下標vector<vector<W>> _matrix; // 鄰接矩陣
};
廣度優先遍歷
void BFS(const V& src)//廣度優先遍歷
{size_t srci = GetVertexIndex(src);// 隊列和標記數組queue<int> q;vector<bool> visited(_vertexs.size(), false);q.push(srci);visited[srci] = true;int levelSize = 1;size_t n = _vertexs.size();while (!q.empty()){// 一層一層出for (int i = 0; i < levelSize; ++i){int front = q.front();//下標q.pop();cout << front << ":" << _vertexs[front] << " ";//下標對應的值// 把front頂點的鄰接頂點入隊列for (size_t i = 0; i < n; ++i){if (_matrix[front][i] != MAX_W){if (visited[i] == false){q.push(i);visited[i] = true;}}}}cout << endl;levelSize = q.size();}cout << endl;
}
深度優先遍歷
void _DFS(size_t srci, vector<bool>& visited)
{cout << srci << ":" << _vertexs[srci] << endl;//訪問起點visited[srci] = true;// 找一個srci相鄰的沒有訪問過的點,去往深度遍歷for (size_t i = 0; i < _vertexs.size(); ++i){if (_matrix[srci][i] != MAX_W && visited[i] == false){_DFS(i, visited);}}}void DFS(const V& src)
{size_t srci = GetVertexIndex(src);vector<bool> visited(_vertexs.size(), false);_DFS(srci, visited);
}
最小生成樹
Kruskal算法
W Kruskal(Self& minTree)
{size_t n = _vertexs.size();//最小生成樹初始化,否則越界minTree._vertexs = _vertexs;minTree._indexMap = _indexMap;minTree._matrix.resize(n);for (size_t i = 0; i < n; ++i){minTree._matrix[i].resize(n, MAX_W);}priority_queue<Edge, vector<Edge>, greater<Edge>> minque;for (size_t i = 0; i < n; ++i){for (size_t j = 0; j < n; ++j){if (i < j && _matrix[i][j] != MAX_W){minque.push(Edge(i, j, _matrix[i][j]));}}}// 選出n-1條邊int size = 0;W totalW = W();UnionFindSet ufs(n);while (!minque.empty()){Edge min = minque.top();minque.pop();if (!ufs.InSet(min._srci, min._dsti))//如果一條邊的兩個端點屬于同一個集合,則形成環{cout << _vertexs[min._srci] << "->" << _vertexs[min._dsti] << ":" << min._w << endl;minTree._AddEdge(min._srci, min._dsti, min._w);ufs.Union(min._srci, min._dsti);++size;totalW += min._w;}else{cout << "構成環:";cout << _vertexs[min._srci] << "->" << _vertexs[min._dsti] << ":" << min._w << endl;}}if (size == n - 1){return totalW;}else{return W();}
}
void TestGraphMinTree()
{const char* str = "abcdefghi";Graph<char, int> g(str, strlen(str));g.AddEdge('a', 'b', 4);g.AddEdge('a', 'h', 8);//g.AddEdge('a', 'h', 9);g.AddEdge('b', 'c', 8);g.AddEdge('b', 'h', 11);g.AddEdge('c', 'i', 2);g.AddEdge('c', 'f', 4);g.AddEdge('c', 'd', 7);g.AddEdge('d', 'f', 14);g.AddEdge('d', 'e', 9);g.AddEdge('e', 'f', 10);g.AddEdge('f', 'g', 2);g.AddEdge('g', 'h', 1);g.AddEdge('g', 'i', 6);g.AddEdge('h', 'i', 7);Graph<char, int> kminTree;cout << "Kruskal:" << g.Kruskal(kminTree) << endl;kminTree.Print();
}
Prim算法
局部貪心
W Prim(Self& minTree, const W& src)
{size_t srci = GetVertexIndex(src);size_t n = _vertexs.size();minTree._vertexs = _vertexs;minTree._indexMap = _indexMap;minTree._matrix.resize(n);for (size_t i = 0; i < n; ++i){minTree._matrix[i].resize(n, MAX_W);}/*set<int> X;set<int> Y;X.insert(srci);for (size_t i = 0; i < n; ++i){if (i != srci){Y.insert(i);}}*/vector<bool> X(n, false);vector<bool> Y(n, true);X[srci] = true;Y[srci] = false;// 從X->Y集合中連接的邊里面選出最小的邊priority_queue<Edge, vector<Edge>, greater<Edge>> minq;// 先把srci連接的邊添加到隊列中//for (size_t i = 0; i < n; ++i){if (_matrix[srci][i] != MAX_W){minq.push(Edge(srci, i, _matrix[srci][i]));}}cout << "Prim開始選邊" << endl;size_t size = 0;W totalW = W();while (!minq.empty()){Edge min = minq.top();minq.pop();// 最小邊的目標點也在X集合,則構成環if (X[min._dsti]){//cout << "構成環:";//cout << _vertexs[min._srci] << "->" << _vertexs[min._dsti] << ":" << min._w << endl;}else{minTree._AddEdge(min._srci, min._dsti, min._w);cout << _vertexs[min._srci] << "->" << _vertexs[min._dsti] << ":" << min._w << endl;X[min._dsti] = true;Y[min._dsti] = false;++size;totalW += min._w;if (size == n - 1)break;for (size_t i = 0; i < n; ++i){if (_matrix[min._dsti][i] != MAX_W && Y[i])//避免重復{minq.push(Edge(min._dsti, i, _matrix[min._dsti][i]));}}}}if (size == n - 1){return totalW;}else{return W();}
}
void TestGraphMinTree(){const char str[] = "abcdefghi";Graph<char, int> g(str, strlen(str));g.AddEdge('a', 'b', 4);g.AddEdge('a', 'h', 8);//g.AddEdge('a', 'h', 9);g.AddEdge('b', 'c', 8);g.AddEdge('b', 'h', 11);g.AddEdge('c', 'i', 2);g.AddEdge('c', 'f', 4);g.AddEdge('c', 'd', 7);g.AddEdge('d', 'f', 14);g.AddEdge('d', 'e', 9);g.AddEdge('e', 'f', 10);g.AddEdge('f', 'g', 2);g.AddEdge('g', 'h', 1);g.AddEdge('g', 'i', 6);g.AddEdge('h', 'i', 7);Graph<char, int> kminTree;cout << "Kruskal:" << g.Kruskal(kminTree) << endl;kminTree.Print();cout << endl << endl;Graph<char, int> pminTree;cout << "Prim:" << g.Prim(pminTree, 'a') << endl;pminTree.Print();cout << endl;for (size_t i = 0; i < strlen(str); ++i){cout << "Prim:" << g.Prim(pminTree, str[i]) << endl;}}
?
鄰接表
template<class W>
struct Edge
{//int _srci;int _dsti; // 目標點的下標W _w; // 權值Edge<W>* _next;Edge(int dsti, const W& w):_dsti(dsti), _w(w), _next(nullptr){}
};template<class V, class W, bool Direction = false>
class Graph
{typedef Edge<W> Edge;
public:Graph(const V* a, size_t n){_vertexs.reserve(n);for (size_t i = 0; i < n; ++i){_vertexs.push_back(a[i]);_indexMap[a[i]] = i;}_tables.resize(n, nullptr);}size_t GetVertexIndex(const V& v){auto it = _indexMap.find(v);if (it != _indexMap.end()){return it->second;}else{//assert(false);throw invalid_argument("頂點不存在");return -1;}}void AddEdge(const V& src, const V& dst, const W& w){size_t srci = GetVertexIndex(src);size_t dsti = GetVertexIndex(dst);// 1->2Edge* eg = new Edge(dsti, w);eg->_next = _tables[srci];//新創建的邊的 _next 指針指向當前 _tables[srci] 所指向的鏈表頭節點_tables[srci] = eg;//更新 _tables[srci] 使其指向新創建的邊 eg,即將新邊插入到鏈表頭部// 2->1if (Direction == false){Edge* eg = new Edge(srci, w);eg->_next = _tables[dsti];_tables[dsti] = eg;}}void Print(){// 頂點for (size_t i = 0; i < _vertexs.size(); ++i){cout << "[" << i << "]" << "->" << _vertexs[i] << endl;}cout << endl;for (size_t i = 0; i < _tables.size(); ++i){cout << _vertexs[i] << "[" << i << "]->";Edge* cur = _tables[i];while (cur){cout << "[" << _vertexs[cur->_dsti] << ":" << cur->_dsti << ":" << cur->_w << "]->";cur = cur->_next;}cout << "nullptr" << endl;}}private:vector<V> _vertexs; // 頂點集合map<V, int> _indexMap; // 頂點映射下標vector<Edge*> _tables; // 鄰接表//表示存儲每個頂點對應的邊鏈表的表頭指針數組
};