洛谷P3003 [USACO10DEC]苹果交货Apple Delivery
首先,这题思路很清晰,因为只有两条路,s->1->2或s->2->1,因此分别用1和2做两遍SPFA,取较小的一个就好了。
这题值得注意的是时间,很多人是70分,你一定是用的裸的SPFA,因为我就是这么干的,然后3个TLE,怎么办呢?这时就要用到SPFA的优化了,哔(不要问我为什么),有请SLF出场!
SLF(Small Label First),意思就是小的在前,具体就是:假设要进队的点是t,队首元素是f,那么如果d[t]< d[f],就把t放队首,否则放队尾。
此时肯定有人问,怎么放队首呢?办法还是出自c++的STl,c++强大的STl中有一个双端队列deque,头尾都可以加元素,这样问题就解决了。它的原理应该和dijkstra是一(bu)样(tong)的。
貌似还有一个优化更好,叫LLL,Large Label Last,可以自行百度,我不多做介绍。
SLF可以优化15%~20%,LLL可以优化50%,自己看情况使用(不过此题SLF就过了)。
下来贴代码:
#include<bits/stdc++.h>
#define inf 2100000000
using namespace std;
struct edge{
int to,next,w;
}e[400001];
int m,n,s,a,b,tot=0;
int d[100001];
int head[100001];
int in[100001];
void addedge(int x,int y,int l){
tot++;
e[tot].to=y;
e[tot].w=l;
e[tot].next=head[x];
head[x]=tot;
}
deque<int> q;
void spfa(int st){
memset(in,0,sizeof(in));
memset(d,127,sizeof(d));
d[st]=0;
in[st]=1;
q.push_front(st);
while(!q.empty()){
int k=q.front();
q.pop_front();
in[k]=0;
for(int i=head[k];i!=0;i=e[i].next){
if(d[k]+e[i].w<d[e[i].to]){
d[e[i].to]=d[k]+e[i].w;
if(!in[e[i].to]){
if(!q.empty()&&d[e[i].to]<d[q.front()]){
q.push_front(e[i].to);
}
else{
q.push_back(e[i].to);
}
}
}
}
}
}
int main(){
cin>>m>>n>>s>>a>>b;
for(int i=1;i<=m;i++){
int x,y,l;
scanf("%d %d %d",&x,&y,&l);
addedge(x,y,l);
addedge(y,x,l);
}
int ans1=0;
int ans2=0;
spfa(a);
ans1+=d[b]+d[s];
spfa(b);
ans2+=d[a]+d[s];
int ans=min(ans1,ans2);
cout<<ans;
return 0;
}