图的基础相关算法有BFS,DFS,拓扑排序, 强连通分支,kruskal,prim,Bellman-Ford,Dijkstra。这些算法思想不难,就是代码容易忘记,所以将代码写在这里,以备复习。本文的代码都用邻接表结构。
图的邻接表结构定义:
struct Edge { int id; Edge* pNext; }; struct Vertex { int id; Edge* pAdj; }; struct ALGraph { vector<Vertex> vec; };
void BFS(const ALGraph& g, int k) { int size = g.vec.size(); vector<int> visit(size, 0); queue<int> que; que.push(k); while (!que.empty()) { int i = que.front(); que.pop(); visit[i] = 1; Edge* p = g.vec[i].pAdj; while (p != NULL) { if (visit[p->id] == 0) { visit[p->id] = 1; que.push(p->id); } p = p->pNext; } } }
void DFS_TR(const ALGraph& g, int k, vector<int>& s, vector<int>& f, int& time, vector<int>& visit) { visit[k] = 1; s[k] = ++time; Edge* p = g.vec[k].pAdj; while (p != NULL) { if (visit[p->id] == 0) DFS_TR(g, p->id, s, f, time, visit); p = p->pNext; } f[k] = ++time; } void DFS(const ALGraph& g) { int size = g.vec.size(); vector<int> visit(size, 0); vector<int> s(size, 0); vector<int> f(size, 0); int time = 0; for (int i = 0; i < size; ++i) { if (visit[i] == 0) DFS_TR(g, i, s, f, time, visit); } }
拓扑排序:借助DFS,将f[]按照逆序输出即可
void DFS_TR(const ALGraph& g, int k, vector<int>& s, vector<int>& f, int& time, vector<int>& visit, stack<int> stk) { visit[k] = 1; s[k] = ++time; Edge* p = g.vec[k].pAdj; while (p != NULL) { if (visit[p->id] == 0) DFS_TR(g, p->id, s, f, time, visit, stk); p = p->pNext; } f[k] = ++time; //先访问完的节点先入栈 stk.push(k); } void DFS(const ALGraph& g, stack<int>& stk) { int size = g.vec.size(); vector<int> visit(size, 0); vector<int> s(size, 0); vector<int> f(size, 0); int time = 0; for (int i = 0; i < size; ++i) { if (visit[i] == 0) DFS_TR(g, i, s, f, time, visit, stk); } } void Topo(const ALGraph& g) { stack<int> stk; DFS(g, stk); while (!stk.empty()) { cout << stk.top() << endl; stk.pop(); } }
SCC:强连通分支,运用两次DFS
void DFS_TR_G(const ALGraph& g, int k, vector<int>& s, vector<int>& f, int& time, vector<int>& visit, stack<int> stk) { visit[k] = 1; s[k] = ++time; Edge* p = g.vec[k].pAdj; while (p != NULL) { if (visit[p->id] == 0) DFS_TR(g, p->id, s, f, time, visit, stk); p = p->pNext; } f[k] = ++time; //先访问完的节点先入栈 stk.push(k); } void DFS_G(const ALGraph& g, stack<int>& stk) { int size = g.vec.size(); vector<int> visit(size, 0); vector<int> s(size, 0); vector<int> f(size, 0); int time = 0; for (int i = 0; i < size; ++i) { if (visit[i] == 0) DFS_TR_G(g, i, s, f, time, visit, stk); } } void DFS_TR_GT(const ALGraph& g, int k, vector<int>& s, vector<int>& f, int& time, vector<int>& visit) { visit[k] = 1; s[k] = ++time; Edge* p = g.vec[k].pAdj; while (p != NULL) { if (visit[p->id] == 0) DFS_TR(g, p->id, s, f, time, visit, stk); p = p->pNext; } f[k] = ++time; } int DFS_GT(const ALGraph& g, stack<int>& stk) { int size = g.vec.size(); vector<int> visit(size, 0); vector<int> s(size, 0); vector<int> f(size, 0); int time = 0; int res = 0; while (!stk.empty()) { int i = stk.top(); stk.pop(); if (visit[i] == 0) { ++res; DFS_TR_GT(g, i, s, f, time, visit); } } return res; } void SCC(const ALGraph& g) { stack<int> stk; DFS_G(g, stk); //计算g的转置图,这步很简单用伪代码,设gt为g的转置 compute gt; int res = DFS_GT(gt, stk); }