题目描述
对于一个含有 $n$ 个点,和 $m$ 条边的 无向图,且边的权值都是 正数
求解从起点 $s$ 到 终点 $t$ 的 最短路径长度
分析
单源点,正权图,求到终点的 最短路径
经典的 单源最短路 裸题,点数的范围是 $2500$,边数的范围是 $12400$
Dijkstra 朴素版 的 时间复杂度 为 $O(n^2)$,本题运算上界是 $6.26 \times 10^6$
Dijkstra 堆优化版 的 时间复杂度 为 $O(m\log n)$,本题运算上界是 $1.36 \times 10^5$
任意选择其中之一都可
(还有,关于spfa他死了)
Code(朴素版Dijkstra)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2510, M = 6210;
int n, m, s, t;
int g[N][N];
int dist[N];
bool st[N];
void dijkstra()
{
memset(dist, 0x3f, sizeof dist);
memset(st, 0, sizeof st);
dist[s] = 0;
for (int i = 1; i <= n; i ++ )
{
int t = -1;
for (int j = 1; j <= n; j ++ )
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
st[t] = true;
for (int j = 1; j <= n; j ++ )
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
}
int main()
{
memset(g, 0x3f, sizeof g);
cin >> n >> m >> s >> t;
while (m -- )
{
int a, b, c;
cin >> a >> b >> c;
g[a][b] = g[b][a] = min(g[a][b], c);
}
dijkstra();
cout << dist[t] << endl;
return 0;
}
Code(堆优化版Dijkstra)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 2510, M = 6210 << 1;
int n, m, s, t;
int h[N], e[M], ne[M], w[M], 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 dijkstra()
{
memset(dist, 0x3f, sizeof dist);
memset(st, 0, sizeof st);
priority_queue<PII, vector<PII>, greater<>> heap;
heap.push({0, s});
dist[s] = 0;
while (!heap.empty())
{
PII t = heap.top();
heap.pop();
st[t.y] = true;
for (int i = h[t.y]; ~i; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[t.y] + w[i])
{
dist[j] = dist[t.y] + w[i];
heap.push({dist[j], j});
}
}
}
}
int main()
{
memset(h, -1, sizeof h);
cin >> n >> m >> s >> t;
while (m -- )
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
dijkstra();
cout << dist[t] << endl;
return 0;
}
堆优化版本的st其实没用上吧,是不是在入队的时候判断一下会更优?
应该是作者忘记写了,st是用来标记堆顶的点是否扩散过,如果扩散过就不再扩散 continue掉 ,提高效率,虽然不用也能过但是很满
记录美好生活
大佬们,spfa在这道题的最坏情况下是O(n*m)=3千多万,为什么不会被卡?一般多少才会被卡
1e8以内不会被卡
3q
彩铅巨巨,欢迎回来~
理论上来讲卡spafa的话这道题是过不了的。不建议使用。但是做法还是可以介绍一下吧?著明就可以了
# why M = 6210 << 1;
# because bidirection
为什么说spfa死了呢,只是在正权图会被卡吗
现在很多出题人会出数据卡SPFA卡成 O(nm)
彩铅巨巨 orz
你好 orz
来迟哩,加油彩铅巨巨
谢谢 w
又开始啦666
科宇大佬好 w
欢迎彩铅大佬回归!
谢谢 w
梦重新开始的地方
是的hh