Dijkstra算法用於求解一個點到所有點的距離
例子
5 5 1(5個點 5條邊 起點為1號節點)
1 2 20(下面5行是5條邊的起點、終點與權值)
2 3 30
3 4 20
4 5 20
1 5 100
代碼
//原版Dijkstra #include<iostream> #include<algorithm> #include<cstdio> #include<cmath> using namespace std; int edges[10002][10002]; int dist[10002]; int visited[10002]; #define inf 0x3f3f3f3f int n, m, s; void Dijkstra() { fill(dist, dist + n+1, inf);//dist數組初始化為inf dist[s] = 0;//將起點的dist設為0 for (int i = 1; i <= n; i++)//因為從起點開始,所以執行n次 { int u = -1, min = inf; for (int j = 1; j <= n; j++)//尋找最短邊 { if (!visited[j] && dist[j] < min) { u = j; min = dist[j]; } } if (u == -1)return; visited[u] = 1;//這里不能忘記 for (int j = 1; j <= n; j++) { if (!visited[j]) { if (min + edges[u][j] < dist[j]) dist[j] = min + edges[u][j]; } } } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); cin >> n >> m >> s; fill(edges[0], edges[0] + 10002 * 10002, inf);//這種寫法在數據量比較大的題目中是會爆內存的 for (int i = 1; i <= m; i++) { int a, b,c; cin >> a >> b >> c; edges[a][b] = c; } Dijkstra(); for (int i = 1; i <= n; i++) printf("%s%d", i == 1 ? "" : " ", dist[i]); }
防止爆內存Dijkstra
題目:https://www.luogu.com.cn/problem/P3371
本題目數據量
但是還是TLE………………
於是使用vector儲存圖,詳見代碼
代碼
//改進vector版Dijkstra #include<iostream> #include<queue> #include<algorithm> #include<cstdio> #include<cmath> #include<vector> using namespace std; typedef pair<int, int> p; //這里最好使用typedef 定義一下下面再用,如果直接vector<pair<int,int>> edges[10002];在OJ編程通不過………… //priority_queue<pair<int, int> > qq; // 注意在兩個尖括號之間一定要留 空格,防止誤判 vector<p> edges[10002]; long long dist[10002]; int visited[10002]; #define inf 0x3f3f3f3f int n, m, s; void Dijkstra() { fill(dist, dist + n+1, inf); dist[s] = 0; for (int i = 1; i <= n; i++) { int u = -1; long long min = inf; for (int j = 1; j <= n; j++) { if (!visited[j] && dist[j] < min) { u = j; min = dist[j]; } } if (u == -1)return; visited[u] = 1; for (int j = 0; j <edges[u].size(); j++)//在以u為起點的所有邊中尋找 { int vv = edges[u][j].first;//是這條邊的終點 if (!visited[vv]) { if (min + edges[u][j].second< dist[vv]) dist[vv] = min + edges[u][j].second; } } } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); cin >> n >> m >> s; for (int i = 1; i <= m; i++) { int a, b, c; cin >> a >> b >> c; edges[a].push_back(make_pair(b, c));//使用每條邊的起始節點作為edges的index,pair里是終點與權值 } Dijkstra(); bool space = false; for (int i = 1; i <= n; i++) { if (visited[i]) printf("%s%d",space==false?"":" ", dist[i]); else printf("%s%s", space == false ? "" : " ", "2147483647"); space = true; } } //測試實例 //5 15 5 //2 2 270 //1 4 89 //2 1 3 //5 5 261 //5 2 163 //5 5 275 //4 5 108 //4 4 231 //3 4 213 //3 3 119 //3 1 77 //3 1 6 //2 4 83 //5 5 196 //5 5 94 //166 163 2147483647 246 0
Dijkstra堆優化
題目:https://www.luogu.com.cn/problem/P4779
#include<iostream> #include<queue> #include<algorithm> #include<cstdio> #include<cmath> using namespace std; #define maxn 100010 #define maxm 500010 #define inf 0x7fffffff struct edge { int to;//終點 int dis;//權值 int next;//下一條邊 //不添加from起點,意義不大 }; struct node { int dis;//權值 int pos;//下標 bool operator <(const node &x)const { return x.dis < dis;//從小到大排序 } }; edge e[maxm]; int head[maxn], dist[maxn], cnt, visited[maxn]; int n, m, s; priority_queue<node>q;//每次出隊的都是dis最小的,節省了(更新后再比,出現更小的再更新此類情況)消耗的時間 void addedge(int u, int v, int w) { cnt++; e[cnt].dis = w; e[cnt].to = v; e[cnt].next = head[u];//head[u]總是臨時存放着同起點的前一條邊,當同起點的后一條邊輸入時,把前一條邊的index賦值給這條邊的next(於是同起點的邊順序是輸入順序的反序) head[u] = cnt; } void Dijkstra() { fill(dist, dist + n + 1, inf); dist[s] = 0; q.push({ 0, s });//加入起點 while (!q.empty()) { node tmp = q.top(); q.pop(); int x = tmp.pos, d = tmp.dis; if (visited[x])continue; visited[x] = 1;//相當於前面的visited[u] = 1; for (int i = head[x]; i; i = e[i].next) { int y = e[i].to; if (dist[y] > dist[x] + e[i].dis) { dist[y] = dist[x] + e[i].dis; q.push({ dist[y], y }); } } } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); cin >> n >> m >> s; for (int i = 1; i <= m; i++) { int a, b, c; cin >> a >> b >> c; addedge(a, b, c); } Dijkstra(); for (int i = 1; i <= n; i++) printf("%s%d", i == 1 ? "" : " ", dist[i]); }