算法学习专栏——spfa
一、spfa求最短路(中等–)
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。
请你求出 1 号点到 n 号点的最短距离,如果无法从 11 号点走到 n 号点,则输出 impossible
。
数据保证不存在负权回路。
输入格式
第一行包含整数 n 和 m。
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
输出格式
输出一个整数,表示 11 号点到 n 号点的最短距离。
如果路径不存在,则输出 impossible
。
数据范围
$$
\begin{flalign}
&1≤n,m≤10^5\
&图中涉及边长绝对值均不超过 10000。&
\end{flalign}
$$
输入样例:
1 |
|
输出样例:
1 |
|
思路
代码
答案(请自己先思考一下再参考)
#include < iostream> #include < algorithm> #include < queue> #include < cstring> using namespace std; const int N = 1e5 + 10; int n, m; int h[N], e[N], ne[N], w[N], idx; int dist[N]; bool st[N]; void add(int a,int b,int c) { e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx++; } void spfa() { memset(dist, 0x3f, sizeof dist); dist[1] = 0; queue< int> q; q.push(1); st[1] = true; while (q.size()){ int t = q.front(); q.pop(); st[t] = false; for (int i = h[t]; ~i; i = ne[i]) { int j = e[i]; if (dist[j] > dist[t] + w[i]) { dist[j] = dist[t] + w[i]; if (!st[j]) { q.push(j); st[j] = true; } } } } if(dist[n] == 0x3f3f3f3f) cout << "impossible"; else cout << dist[n]; } int main() { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); memset(h, -1, sizeof h); cin >> n >> m; for (int i = 0; i < m; i++) { int a, b, c; cin >> a >> b >> c; add(a, b, c); } spfa(); return 0; }
二、spfa判断负环(中等-)
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。
请你判断图中是否存在负权回路。
输入格式
第一行包含整数 n 和 m。
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
输出格式
如果图中存在负权回路,则输出 Yes
,否则输出 No
。
数据范围
$$
\begin{flalign}
&1≤n≤2000\
&1≤m≤10000\
&图中涉及边长绝对值均不超过 10000。&
\end{flalign}
$$
输入样例:
1 |
|
输出样例:
1 |
|
思路
录屏
代码
答案(请自己先思考一下再参考)
#include < iostream> #include < cstring> #include < cstdio> #include < algorithm> #include < queue> using namespace std; const int N = 1e5 + 10; int e[N],ne[N],h[N],w[N],idx; bool st[N]; int dist[N],cnt[N]; int n,m; void add(int a,int b,int c) { e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx++; } int spfa() { memset(dist,0x3f,sizeof dist); dist[1] = 0; queue< int> q; for (int i = 1; i <= n; i++) { st[i] = true; q.push(i); } while (q.size()) { int t = q.front(); q.pop(); st[t] = false; for (int i = h[t]; i != -1; i = ne[i]) { int j = e[i]; if (dist[j] > dist[t] + w[i]) { dist[j] = dist[t] + w[i]; cnt[j] = cnt[t] + 1; if (cnt[j] >= n) return true; if (!st[j]) { q.push(j); st[j] = true; } } } } return false; } int main() { scanf("%d %d",&n,&m); memset(h,-1,sizeof h); while (m--) { int a,b,c; scanf("%d %d %d",&a,&b,&c); add(a,b,c); } if (spfa()) printf("Yes"); else printf("No"); return 0; }