bzoj2100 [Usaco2010 DEC]Apple Delivery苹果贸易

题目描述

一张P个点的无向图,C条正权路。CLJ要从Pb点(家)出发,既要去Pa1点NOI赛场拿金牌,也要去Pa2点CMO赛场拿金牌。(途中不必回家)可以先去NOI,也可以先去CMO。当然神犇CLJ肯定会使总路程最小,输出最小值。

题解:做两遍spfa,找出从起点开始先去pa1或者先去pa2的最小值

需要用一下spfa的优化,每次进行入队的时候都与队头进行比较,如果比队头小就放在队头,否则放队尾。

 

#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
#define maxm 200005
int dis[maxn],head[maxn],q[maxn];
bool vis[maxn];
struct edge{
    int next,to,w;
}e[maxm*2];
int n,m,s,t1,t2;
int ans=2000000000,cnt;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void insert(int u,int v,int w){
    cnt++;
    e[cnt].next=head[u];e[cnt].to=v;e[cnt].w=w;
    head[u]=cnt;
}    
void spfa(int x){
    memset(dis,127,sizeof dis);
    vis[x]=1;dis[x]=0;q[0]=x;
    int top=0,tail=1;
    while(top!=tail)
    {
        int now=q[top];top++;
        if(top==100001)top=0;
        for(int i=head[now];i;i=e[i].next){
            int p=e[i].to;
            if(dis[p]>dis[now]+e[i].w){
                dis[p]=dis[now]+e[i].w;
                if(!vis[p]){
                    vis[p]=1;
                    if(dis[p]<dis[q[top]]){
                        top--;if(top<0)top=100000;
                        q[top]=p;    
                    }
                    else{
                        q[tail++]=p;
                        if(tail==100001)tail=0;
                    }
                }
            }
        }
        vis[now]=0;
    }
}
int main(){
    m=read();n=read();s=read();t1=read();t2=read();
    int u,v,w;
    for(int i=1;i<=m;i++){
        u=read();v=read();w=read();
        insert(u,v,w);insert(v,u,w);
    }
    spfa(t1);
    ans=dis[s]+dis[t2];
    spfa(t2);
    ans=min(ans,dis[s]+dis[t1]);
    printf("%d",ans);
}

 

posted @ 2017-10-19 15:00  Elfish?  阅读(146)  评论(0编辑  收藏  举报