一道综合性很强的题。
有负权无负环的单源最短路:拓扑排序(所有正权连通块间) + Dijkstra(每个正权连通块内)
DFS求出所有连通块,拓扑排序按照块的拓扑序计算最短距离,遍历到该块时块内执行Dijkstra求出该块内所有点的最短距离,若更新时遇到不属于该块的点,则处理连通块的入度并判断是否将它所在的连通块入队。
关于SPFA,他死了。。。
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 25010, M = 150010;
int h[N], e[M], w[M], ne[M], idx = 1;
int dist[N], st[N];
int id[N];
vector<int> block[N];
int d[N];
int bcnt;
queue<int> q;
int n, P, R, s;
void add(int a, int b, int c){
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
void dfs(int a, int bid){
id[a] = bid;
block[bid].push_back(a);
for(int i=h[a];i;i=ne[i]){
int b = e[i];
if(!id[b]) dfs(b, bid);
}
}
void dijkstra(int t){
priority_queue<PII, vector<PII>, greater<PII>> heak;
for(auto it: block[t]){
heak.push({dist[it], it});
}
while(heak.size()){
int a = heak.top().second;
heak.pop();
if(st[a]) continue;
st[a] = 1;
for(int i=h[a];i;i=ne[i]){
int b = e[i];
dist[b] = min(dist[b], dist[a]+w[i]);
if(id[b]==t){
heak.push({dist[b], b});
}
else{
d[id[b]] --;
if(!d[id[b]]) q.push(id[b]);
}
}
}
}
void toposort(){
memset(dist, 0x3f, sizeof(dist));
dist[s] = 0;
for(int i=1;i<=bcnt;i++){
if(!d[i]){
q.push(i);
}
}
while(q.size()){
int t = q.front();
q.pop();
dijkstra(t);
}
}
int main(){
scanf("%d%d%d%d", &n, &P, &R, &s);
while(P--){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
add(b, a, c);
}
for(int i=1;i<=n;i++){
if(!id[i]) dfs(i, ++bcnt);
}
while(R--){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
d[id[b]] ++;
}
toposort();
for(int i=1;i<=n;i++){
if(dist[i]>0x3f3f3f3f/2) printf("NO PATH\n");
else printf("%d\n", dist[i]);
}
return 0;
}