此题其实比较水的。。。

首先我们来分析题目,我们假设,贝茜和艾尔西在i点相遇后贝西开始扛艾尔西,那么代价为多少呢?

显然,代价=贝茜到i点的最小代价+艾尔西到i点的最小代价+贝茜和艾尔西一起到n点的最小代价。

我们分开解决,首先贝茜到i点的最小代价=走的最少步数*b,而走的步数,我们跑一遍以spfa(1)就可以轻松求出来了!

同理。艾尔西,我们跑spfa(2)就可以求出,而共同走到n,我们跑spfa(n)即可~

意思是,我们先跑三遍spfa:spfa(1),spfa(2),spfa(n),分别求出1到i的步数,设为dis[i][1].2到i的最小步数,设为dis[i][2],n到i的最小步数,设为dis[i][3].

那么我们就可以知道,在i点集合后再背负到n的代价为:dis[i][1]b+dis[i][2]e+dis[i][3]*p;

所以我们只需要O(n)枚举集合点i,然后O(1)计算取最小就好了

至于如果p>b+e怎么办,其实此时最优方案就是各走各的,就相当于在n点集合。

以下为代码:

#include<bits/stdc++.h> using namespace std; #define int long long//三年oi一场空,不开long long见祖宗. const int N=4e4+1,inf=1e17; struct node{ int v,nex;
}t[N<<1]; int len,las[N]; int dis[N][4],n; bool vis[N];
inline void add(int u,int v){//加双向边 len++;
    t[len].v=v;
    t[len].nex=las[u],las[u]=len;
    len++;
    t[len].v=u;
    t[len].nex=las[v],las[v]=len;
}
inline void spfa(int z,int y){//spfa,当然,它死了... queue<int>s;
    s.push(z);
    dis[z][y]=0; while(!s.empty()){ int x=s.front();
        s.pop();
        vis[x]=0; for(int i=las[x];i;i=t[i].nex){ int v=t[i].v; if(dis[v][y]>dis[x][y]+1){
                dis[v][y]=dis[x][y]+1; if(!vis[v]){
                    vis[v]=1;
                    s.push(v);
                }
            }
        }
    }
}
main(){
    memset(dis,0x3f3f,sizeof(dis));//初始化 int b,e,p,m;
    scanf("%lld%lld%lld%lld%lld",&b,&e,&p,&n,&m); for(int i=1;i<=m;++i){ int u,v;
        scanf("%lld%lld",&u,&v);
        add(u,v);
    }
    spfa(1,1),spfa(2,2),spfa(n,3);//跑spfa,因为空间只需要3*n,所以用此方法。。。 long long ans=inf; for(int i=1;i<=n;++i){//枚举集合点 long long now=1LL*b*dis[i][1]+1LL*e*dis[i][2]+1LL*p*dis[i][3];//计算最小代价 ans=min(ans,now);
    }
    printf("%lld",ans); return 0;
}