1. 程式人生 > >題解 P4874 【[USACO14DEC] Piggyback_Silver 揹負式運輸(銀)】

題解 P4874 【[USACO14DEC] Piggyback_Silver 揹負式運輸(銀)】

此題其實比較水的。。。

首先我們來分析題目,我們假設,貝茜和艾爾西在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; }