1. 程式人生 > 實用技巧 >P3110 [USACO14DEC]Piggy Back S 題解

P3110 [USACO14DEC]Piggy Back S 題解

題解 [USACO14DEC]Piggy Back S

Description

給出一個無向圖,Bessie從1號倉庫走到n號(每次花費B), Elsie從2號倉庫走到n號(每次花費E),如果兩個人走同一條路花費P,求總花費最小。
輸入B,E,P,n,m和m條邊的聯通情況。
輸出最少花費。

SimpleInput

4 4 5 8 8 
1 4 
2 3 
3 4 
4 7 
2 5 
5 6 
6 8 
7 8 

SimpleOutput

22

資料範圍

\(1\le n,m,b,e,p\le 4×10^4,n \ge 3\)

Solution

首先這道題明顯是一個最短路,和在一起考慮有一點麻煩,所以我們分開考慮。
對於 Bessie 和 Elsie 來說,他們走到任意一個點的最短路是非常好算的。假設他們現在都走到了點 \(i\)

,並且想要一起走到終點,那麼我們只需要求出從點 \(n\) 到點 \(i\) 的距離,最後對所有的值取最小值即可。
時間複雜度為 \(\mathcal{O(k\times n)}\) (SPFA 時間複雜度)

Code

#include <bits/stdc++.h>
using namespace std;

const int N = 100007;

int dis[4][N],inq[4][N],head[N];
int m,n,u,v,b,e,p,cnt = 0,ans = 2147483647;

struct node {
	int v,nxt;
	node() {}
	node(int _v,int _nxt) {
		v = _v; nxt = _nxt;
	}
}E[N];

template <class T> inline void read(T &x) {
	x = 0;
	int p = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-') p = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9') {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	x = x * p;
}

void add_edge(int u,int v) {
	E[++cnt] = node(v,head[u]);
	head[u] = cnt;
}

void spfa(int id,int st) {      //SPFA
	int wi;
	if(id == 1) wi = b;
	if(id == 2) wi = e;
	if(id == 3) wi = p;
	queue <int> q;
	memset(dis[id],0x3f,sizeof(dis[id]));
	memset(inq[id],0,sizeof(inq[id]));
	dis[id][st] = 0; inq[id][st] = 1;
	q.push(st);
	while(!q.empty()) {
		int u = q.front(); q.pop();
		inq[id][u] = 0;
		for(int i = head[u];i != 0;i = E[i].nxt) {
			int v = E[i].v;
			if(dis[id][v] > dis[id][u] + wi) {
				dis[id][v] = dis[id][u] + wi;
				if(!inq[id][v]) {
					inq[id][v] = 1;
					q.push(v);
				}
			}
		}
	}
}

int main() {
	read(b); read(e); read(p); read(n); read(m);
	for(int i = 1;i <= m;i++) {
		read(u); read(v);
		add_edge(u,v);
		add_edge(v,u);
	}
	spfa(1,1); spfa(2,2); spfa(3,n);
        // 1表示Bessie,2表示Elsie,3表示他們一起走
	for(int i = 1;i <= n;i++) {
		ans = min(ans,dis[1][i] + dis[2][i] + dis[3][i]);//取最小值
	}
	printf("%d\n",ans);
	return 0;
}