vector邻接表建图+dijkstra模板
生活随笔
收集整理的這篇文章主要介紹了
vector邻接表建图+dijkstra模板
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
本文節點的編號從0開始計算
思路
這個復雜度是O(N^2)
C++實現
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <queue> using namespace std; using LL = long long; const int inf = 0x3f3f3f3f; const int MAX_E = 1e5+5; // 最大邊數 const int MAX_V = 1e4+5; // 最大節點數 int V, E; // 點、邊 struct edge{ int to, w; }; vector<edge> G[MAX_E]; bool vis[MAX_V]; int dis[MAX_V]; // 到源點的距離 void input(); void Build(int x, int y, int w); void dijkstra(int s); int main() {input();dijkstra(0);return 0; }void Build(int x, int y, int w = 1) {edge e; e.to = y; e.w = w;G[x].push_back(e); }void input() {int a,b,w;edge e;cin >> V >> E;for (int i = 0; i < E; i++){cin >> a >> b >> w; // 帶權//cin >> a >> b; // 不帶權Build(a, b, w);Build(b, a, w); // 無向} }void dijkstra(int s) {memset(dis, inf, sizeof(vis)); dis[s] = 0;memset(vis, false, sizeof(vis));int now = s;for (int i = 0; i < V; i++) // 循環V次,i沒有特殊意義{vis[now] = true;for (int j = 0; j < G[now].size(); j++) // 遍歷now的出度{if (!vis[G[now][j].to]) // 如果第j條出度連向的節點未被訪問{dis[G[now][j].to] = min( dis[G[now][j].to], dis[now] + G[now][j].w); // 松弛}}int Min = inf, pos = 0; // 找出未被訪問的節點中距離最短的那個,這一步可以堆優化,即用優先隊列避免遍歷V次for (int i = 0; i < V; i++) // 如果結點從1開始,遍歷[1,V]{if (!vis[i] && dis[i] < Min){Min = dis[i];pos = i;}}now = pos;}for (int i = 0; i < V; i++) printf("%d->%d=%d\n", s, i, dis[i]); }借用書上的例圖,并將它看作是有向圖,當然只要把input函數里邊的第二個Build注釋掉就是有向圖了。
輸入
5 8 0 2 10 0 4 30 0 5 100 1 2 5 2 3 50 3 5 10 4 3 20 4 5 60輸出
0->0=0 0->1=15 0->2=10 0->3=50 0->4=30堆優化
原理是優化“尋找未被訪問的節點中離源點最近的那個”這一步。本來是遍歷,所以復雜度是O(N*N),如果改用優先隊列存儲這些節點,就可以將復雜度改進為O(NlogN)
參考了https://www.cnblogs.com/Renyi-Fan/p/7508098.html
堆優化偽算法 首先定義新的數據類型node,存儲點編號和點到源點的距離,也可以用pair代替 然后定義仿函數,為優先隊列提供自定義的出隊優先級源點入隊(入隊的是node對象,含編號和距離) 當隊列非空,循環下面步驟記錄隊首元素的點編號和距離 min_i, min_d出隊如果min_i 被訪問過,跳過這輪循環標記min_i已訪問遍歷min_i的出度記錄第i條邊連向的結點to,以及這條邊的權w如果to已被訪問,跳過此輪循環松弛node(to, dis[to]) 入隊代碼
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <queue> using namespace std; using LL = long long; using PII = pair<int, int>; // first記錄點編號,second記錄邊權 const int inf = 0x3f3f3f3f; const int MAX_E = 1e5+5; // 最大邊數 const int MAX_V = 1e4+5; // 最大節點數 int V, E; // 點、邊 struct edge{ int to, w; }; struct cmp {bool operator () (const PII & P1, const PII &P2) const { return P1.second > P2.second; } // 距離短的優先 }; vector<edge> G[MAX_E]; bool vis[MAX_V]; int dis[MAX_V]; // 到源點的距離 void input(); void Build(int x, int y, int w); void dijkstra(int s); void dijkstra_2(int s); // 堆優化版本 int main() {input();dijkstra(0);cout << endl;dijkstra_2(0);return 0; }void Build(int x, int y, int w = 1) {edge e; e.to = y; e.w = w;G[x].push_back(e); }void input() {int a,b,w;edge e;cin >> V >> E;for (int i = 0; i < E; i++){cin >> a >> b >> w; // 帶權//cin >> a >> b; // 不帶權Build(a, b, w);Build(b, a, w); // 無向} }void dijkstra(int s) // 未優化 {memset(dis, inf, sizeof(vis)); dis[s] = 0;memset(vis, false, sizeof(vis));int now = s;for (int i = 0; i < V; i++) // 循環V次,i沒有特殊意義{vis[now] = true;for (int j = 0; j < G[now].size(); j++) // 遍歷now的出度{if (!vis[G[now][j].to]) // 如果第j條出度連向的節點未被訪問{dis[G[now][j].to] = min( dis[G[now][j].to], dis[now] + G[now][j].w); // 松弛}}int Min = inf, pos = 0; // 找出未被訪問的節點中距離最短的那個,這一步可以堆優化,即用優先隊列避免遍歷V次for (int i = 0; i < V; i++) // 如果結點從1開始,遍歷[1,V]{if (!vis[i] && dis[i] < Min){Min = dis[i];pos = i;}}now = pos;}for (int i = 0; i < V; i++) printf("%d->%d=%d\n", s, i, dis[i]); }struct node {int i; // 節點編號int d; // 到源點的距離node(int ii = -1, int dd = inf) : i(ii), d(dd){} };struct Cmp // 仿函數 {bool operator()(const node & n1, const node & n2) { return n1.d > n2.d; } // 距離短的優先出隊 };priority_queue<node, vector<node>, Cmp> Q;void dijkstra_2(int s) // 堆優化 {node n;int min_i, min_d; // 存距離源點最近的點編號和距離memset(dis, inf, sizeof(dis)); memset(vis, false, sizeof(vis));dis[s] = 0;Q.push(node(s, dis[s]));while (!Q.empty()){n = Q.top();Q.pop();min_i = n.i;min_d = n.d;if (vis[min_i]) continue; // 如果 min_i 已被訪問,不重復處理vis[min_i] = true;for (int i = 0; i < G[min_i].size(); i++) // 遍歷 min_i 的邊{int to = G[min_i][i].to; // min_i的第i條邊連向的節點int w = G[min_i][i].w; // 邊權if (!vis[to]) { dis[to] = min( dis[to], dis[min_i] + w ); // 松弛Q.push(node(to, dis[to]));}}}for (int i = 0; i < V; i++) printf("%d->%d=%d\n", s, i, dis[i]); }附一組測試數據
輸出
0->0=0 0->1=5 0->2=8 0->3=7 0->4=4 0->5=30->0=0 0->1=5 0->2=8 0->3=7 0->4=4 0->5=3總結
以上是生活随笔為你收集整理的vector邻接表建图+dijkstra模板的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vector邻接表建图+DFS+BFS
- 下一篇: 用fgets替代gets