算法笔记图论图论
scandi图的存储(记录常用的三种
一.邻接矩阵
直接通过二维数组存储,例如
二.vector 存储
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <vector> using namespace std;
int V = 5; vector<vector<int>> adjList(V);
void addEdge(int u, int v, bool directed = false) { adjList[u].push_back(v); if (!directed) { adjList[v].push_back(u); } }
|
三.伪邻接表(链式向前星
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <iostream> using namespace std; const int v = 5; struct ty { int t, next; }edge[100]; int head[100]; int cnt = 0; void insertedge(int x, int y) { edge[++cnt].t = y; edge[cnt].next = head[x]; head[x] = cnt; }
|
欧拉图
具有欧拉回路的图就是欧拉图
如果图中的一个路径包含几个边恰好一次,该路径就是欧拉路径
如果一个回路是欧拉路径,该回路就是欧拉回路
以上的前提就是,该图为连通图,一旦有不连通的点,上面条件都不可能达到
实则就是计算机图的连通性以及每个点的度数
拓扑排序
该排序常常用来判断有向图是否有环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #include <iostream> #include <cstring> #include <queue> #include <vector> using namespace std; int n, m; struct ty { int t, next; }edge[100010]; int cnt = 0; int head[1010]; void insertedge(int x, int y) { edge[++cnt].t = y; edge[cnt].next = head[x]; head[x] = cnt; } int inc[1010]; vector<int> ans; queue<int> q;
void tuopu() { for (int i = 1; i <= n; i++) { if (inc[i] == 0) q.push(i); } while (!q.empty()) { int x = q.front(); q.pop(); ans.push_back(x); for (int i = head[x]; i != -1; i = edge[i].next) { inc[edge[i].t]--; if (inc[edge[i].t] == 0) q.push(edge[i].t); } } }
int main() { cin >> n >> m; memset(head, -1, sizeof(head)); for (int i = 1; i <= m; i++) { int x, y; scanf("%d%d", &x, &y); inc[y]++; insertedge(x, y); } tuopu(); if (ans.size() < n) cout << -1 << endl; else { for (auto i : ans) { cout << i << endl; } } return 0; }
|
下面代码和算法具体解释,等有空再写
最短路
树中的最短路------一般采用dfs解决
有向无环图--------一般采用拓扑排序解决
边权全相等--------一般采用bfs解决
当然还有以下算法用于求其他类型图中的最短路(下面代码的图存储都采用伪邻接表
一.Dijkstra(迪杰斯特拉
djs 算法常常用来解决没有负权边的图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| #include <iostream> #include <cstring> #include <queue> using namespace std; struct ty { int t, len, next; }edge[200010]; int head[1010]; int vis[1010]; int dis[1010]; int cnt = 0; struct ty1 { int x, dist; bool operator<(const ty1& a) const { return dist > a.dist; } }; void addedge(int x, int y, int v) { edge[++cnt].t = y; edge[cnt].len = v; edge[cnt].next = head[x]; head[x] = cnt; } priority_queue<ty1> q; int djs(int s, int t) { memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); dis[s] = 0; ty1 tmp1; tmp1.x = s, tmp1.dist = 0; q.push(tmp1); while (!q.empty()) { ty1 tmp2 = q.top(); q.pop(); if (vis[tmp2.x]) continue; vis[tmp2.x] = 1; for (int i = head[tmp2.x]; i != -1; i = edge[i].next) { int x = edge[i].t; int k = edge[i].len; if (k + dis[tmp2.x] < dis[x]) { dis[x] = k + dis[tmp2.x]; ty1 nex; nex.x = x, nex.dist = dis[x]; q.push(nex); } } } if (dis[t] >= 0x3f3f3f3f) return -1; else return dis[t]; } int main() { int n, m, s, t; cin >> n >> m >> s >> t; memset(head, -1, sizeof(head)); for (int i = 1; i <= m; i++) { int x, y, v; cin >> x >> y >> v; addedge(x, y, v); addedge(y, x, v); } cout << djs(s, t) << endl; return 0; }
|
二.由 Bellman-Ford 优化后的 SPFA 算法
spfa 算法一般只有在出现了负权边的情况下才使用,因为它在极坏情况下可能退化为 o(n^3)的时间复杂度,很大概率被卡
如果图中出现 负环 ,此算法会出现死循环,当然反过来也就可以通过 卡循环次数 来判断图中是否含有 负环
如果同一个点被入队 n 次,即可证明图中必然存在 负环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| #include <iostream> #include <cstring> #include <queue> using namespace std; struct ty { int t, len, next; }edge[200010]; int dis[1010]; int vis[1010]; int head[1010]; int cnt = 0; void addedge(int x, int y, int v) { edge[++cnt].t = y; edge[cnt].len = v; edge[cnt].next = head[x]; head[x] = cnt; } queue<int> q; int spfa(int s, int t) { memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); dis[s] = 0; q.push(s); vis[s] = 1; while (!q.empty()) { int tmp = q.front(); q.pop(); vis[tmp] = 0; for (int i = head[tmp]; i != -1; i = edge[i].next) { if (dis[tmp] + edge[i].len < dis[edge[i].t]) { dis[edge[i].t] = dis[tmp] + edge[i].len; if (vis[edge[i].t] == 0) { q.push(edge[i].t); vis[edge[i].t] = 1; } } } } if (dis[t] >= 0x3f3f3f3f) return -1; else return dis[t]; } int main() { int n, m, s, t; cin >> n >> m >> s >> t; memset(head, -1, sizeof(head)); for (int i = 1; i <= m; i++) { int x, y, v; cin >> x >> y >> v; addedge(x, y, v); addedge(y, x, v); } cout << spfa(s, t) << endl; return 0; }
|