题目链接:Delivery Route
就是有负权的最短路,但是卡了spfa,由于x条路是双向的且为正,故我们可以缩点之后对块内跑Dijkstra,然后拓扑排序合并答案。
但是我们对spfa优化一下就可以了(卡常专家)。
我们都知道spfa有一个优化是SLF,就是用双端队列。
这道题我们再加上一个容错值,如果当前的队首值大于当前要插入的值加上容错值,那么当前值放到队首,否则队尾。
然后再来一个优化,就是随机数大法,随便判断下点的大小选择是否交换(超级重要,随机数防卡),则队列首位交换。
就OK啦!!!
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N=25010;
int n,x,y,s,d[N],eps; bool vis[N];
vector<int> v1[N],v2[N];
inline void add(int a,int b,int c){v1[a].push_back(b); v2[a].push_back(c);}
inline void spfa(){
deque<int> q; q.push_back(s); vis[s]=1; memset(d,inf,sizeof d); d[s]=0;
while(q.size()){
if(q.front()>q.back()) swap(q.front(),q.back());
int u=q.front(); q.pop_front(); vis[u]=0;
for(int i=0,v,w;i<v1[u].size();i++){
v=v1[u][i],w=v2[u][i];
if(d[v]>d[u]+w){
d[v]=d[u]+w; if(vis[v]) continue;
if(q.size()&&q.front()+eps<w) q.push_front(v);
else q.push_back(v); vis[v]=1;
}
}
}
}
signed main(){
scanf("%d %d %d %d",&n,&x,&y,&s); eps=(int)sqrt(n)/10;
for(int i=1,a,b,c;i<=x;i++) scanf("%d %d %d",&a,&b,&c),add(a,b,c),add(b,a,c);
for(int i=1,a,b,c;i<=y;i++) scanf("%d %d %d",&a,&b,&c),add(a,b,c);
spfa();
for(int i=1;i<=n;i++)
if(d[i]==inf) puts("NO PATH");
else printf("%d\n",d[i]);
return 0;
}