普通spfa最坏情况O(nm),会被本题卡。我找到一个spfa优化的做法。
SLF(Small Label First) 双端队列优化,也被戏称为“酸辣粉优化”
优化思路:将原队列改成双端队列,对要加入队列的点 p,如果 dist[p] 小于队头元素 u 的 dist[u],将其插入到队头,否则插入到队尾。
不推荐,因为y总说这是对数据做优化,但竞赛的时候是不知道数据的,想卡还是会被卡。因此正解是做法二
下面是做法一(spfa SLF优化 可以AC本题)
#include<bits/stdc++.h>
using namespace std;
const int N = 2.5e4+10, M = 1.5e5;
#define inf 0x3f3f3f3f
int dist[N], h[N], e[M], ne[M], w[M], idx;
bool st[N];
int t, r, p, s;
void add(int x, int y, int z){
e[idx] = y, ne[idx] = h[x], w[idx] = z, h[x] = idx++;
}
void spfa(int ts)
{
memset(dist, 0x3f,sizeof dist);
dist[ts] = 0;
deque<int> q;
q.push_front(ts);
st[ts] = true;
while(q.size())
{
int t = q.front();
q.pop_front();
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])
{
if(dist[j]>dist[q.front()])
q.push_back(j);
else q.push_front(j);
st[j] = true;
}
}
}
}
}
int main()
{
scanf("%d%d%d%d", &t, &r, &p, &s);
memset(h, -1, sizeof h);
for(int i=0;i<r;++i){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, c);
}
for(int i=0;i<p;++i){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
spfa(s);
for(int i=1;i<=t;++i){
if(dist[i]!=inf) printf("%d\n", dist[i]);
else puts("NO PATH");
}
return 0;
}