洛谷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;
}
posted @ 2017-07-02 21:01  玫葵之蝶  阅读(123)  评论(0编辑  收藏  举报