1. 程式人生 > >SPFA板子 (背景:Luogu P3371 單源最短路徑)

SPFA板子 (背景:Luogu P3371 單源最短路徑)

數組 ons orange radius site 是否 -c class 所在


Luogu P3371 單源最短路徑

題目描述

如題,給出一個有向圖,請輸出從某一點出發到所有點的最短路徑長度。

輸入輸出格式

輸入格式:

第一行包含三個整數N、M、S,分別表示點的個數、有向邊的個數、出發點的編號。

接下來M行每行包含三個整數Fi、Gi、Wi,分別表示第i條有向邊的出發點、目標點和長度。

輸出格式:

一行,包含N個用空格分隔的整數,其中第i個整數表示從點S出發到點i的最短路徑長度(若S=i則最短路徑長度為0,若從點S無法到達點i,則最短路徑長度為2147483647)

輸入輸出樣例

輸入樣例#1:
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4

輸出樣例#1:
0 2 4 3

分析:

啊無負邊權的有向圖的單源最短路徑

代碼+註釋:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <queue>
 4 #include <vector>
 5 #define MAXN 10005
 6 #define MAXM 500005
 7 using namespace std;
 8 
 9 const long long MAX = 2147483647;
10 
11 int n, m, p_st;
12 int x, y, d;
13 vector<int> l[MAXN], dis[MAXN]; //采用鄰接表的存儲方式 14 int ans_dis[MAXN]; //答案儲存數組 15 bool visited[MAXN]; //標記是否被訪問過 16 17 void read(int a, int b, int d) { //鄰接表的讀入 18 l[a].push_back(b); 19 dis[a].push_back(d); 20 } 21 22 void spfa() { //不就是按照BFS打一波… 23 24 queue<int> q; //
新建隊列 25 visited[p_st] = true; //源點設為已經訪問過了 26 ans_dis[p_st] = 0; //到源點的最短路徑為0 27 q.push(p_st); //進隊開始BFS 28 29 while (!q.empty()) { //開始BFS 30 int now = q.front(); //now為目前所在的點 31 for (int i = 0; i < l[now].size(); i++) { //在它周圍可以去到的點裏繞一圈 32 int u = l[now][i], v = dis[now][i]; //u表示目前遍歷到的點 v為目前的點到u的距離 33 if (ans_dis[u] > ans_dis[now] + v) //若可更新距離 34 { 35 ans_dis[u] = ans_dis[now] + v; //更新 36 if (!visited[u]) { 37 visited[u] = true; //標記訪問過 38 q.push(u); //拉進隊列 39 } 40 } 41 } 42 43 visited[now] = false; // 不要忘記打這一句兄dei SFPA和BFS不同點 44 q.pop(); // 出隊 45 } 46 47 } 48 49 int main() { 50 51 scanf("%d%d%d", &n, &m, &p_st); //N為點的個數 M為有向邊的個數 P_ST為出發點的編號 52 for (int i = 1; i <= n; i++) 53 ans_dis[i] = MAX / 3; //當然是為了防止判斷的時候爆炸而設定的 54 for (int i = 1; i <= m; i++) { 55 scanf("%d%d%d", &x, &y, &d); 56 read(x, y, d); 57 } 58 59 spfa(); 60 61 for (int i = 1; i <= n; i++) 62 if (ans_dis[i] == MAX / 3) printf("%lld ", MAX); //到不了這個點 63 else printf("%d ", ans_dis[i]); //到得了就輸出 64 65 return 0; 66 }

(僅供個人復習使用)

SPFA板子 (背景:Luogu P3371 單源最短路徑)