1. 程式人生 > >P3110 [USACO14DEC]馱運Piggy Back-最短路,spfa

P3110 [USACO14DEC]馱運Piggy Back-最短路,spfa

Bessie 和 Elsie在不同的區域放牧,他們希望花費最小的能量返回穀倉。從一個區域走到一個相連區域,Bessie要花費B單位的能量,Elsie要花費E單位的能量。

如果某次他們兩走到同一個區域,Bessie 可以揹著 Elsie走路,花費P單位的能量走到另外一個相連的區域。當然,存在P>B+E的情況。

相遇後,他們可以一直揹著走,也可以獨立分開。

Bessie和Elsie分別從1和2出發到n,如果某一點會相遇,可以選擇剩下的路兩個人一起走或者分開走。

因為只有一次相遇且不會一起走然後又分開,這樣就對1,2,n三個點各跑一次最短路

最後列舉每一個點(相遇點)

ans=min(dis_b[i]*b+dis_e[i]*e+dis_n[i]*p);

相遇前b走過的路程*b+相遇前e走過的路程*e+一起走的路程*p;

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 8e4+3;
int dis_b[maxn],dis_e[maxn],dis_n[maxn],head[maxn];
bool vis[maxn];
int cnt,b,e,p,n,m,ans=2147483647;
const int INF = 2147483647;
queue<int> q;
struct node
{
    int next,to;
}E[maxn*10];
void add(int x,int y)
{
    E[++cnt].next=head[x];
    E[cnt].to=y;
    head[x]=cnt;
}
void spfa(int s,int *dis)
{
    memset(vis,0,sizeof(vis));
    fill(dis+1, dis+1+n, INF);
    dis[s]=0;
    vis[s]=true;
    q.push(s);
    while(!q.empty()){
        int now=q.front();q.pop();vis[now]=false;
        for(int i=head[now];i;i=E[i].next){
            int to=E[i].to;
            if(dis[to]>dis[now]+1){
                dis[to]=dis[now]+1;
                if(!vis[to]){
                    q.push(to);
                    vis[to]=true;
                }
            }
        }
    }
}
int main()
{
    scanf("%d%d%d%d%d",&b,&e,&p,&n,&m);
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    spfa(1,dis_b);spfa(2,dis_e);spfa(n,dis_n);
    for(int i=1;i<=n;i++){
        ans=min(ans,dis_b[i]*b+dis_e[i]*e+dis_n[i]*p);
    }
    printf("%d",ans);
    return 0;
}