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

P3110 [USACO14DEC]Piggy Back S 題解

Link

P3110 [USACO14DEC]Piggy Back S

solve

這道題很早以前做過,所以想清楚也就好了。

對於Bessie和Elsie來說,只能背一次,背上了就不能下來了,所以我們可以列舉背的點,我們可以算出Bessie到背的點的最短路和Elsie到背的點最短路,加上背的點到終點的最短路,都是可以提前預處理出來的,最後取一個min就好了。

code

#include <bits/stdc++.h>//萬能頭大法好

using namespace std;

const int N = 1e7;
const int maxn = 200005;
const int maxm = 500005;

typedef long long ll; //做題的好習慣
typedef long double ld;

#define ms(a) memset(a, 0, sizeof(a))

int n, m, a, b, c;//a,b,c分別是題目中的B、E、P

struct Edge{
	int nxt, to, w;
}e[maxm];

int head[maxn], cnt;

void addEdge(int u, int v, int w) {
	e[++cnt] = (Edge){head[u], v, w}, head[u] = cnt;
}

int vis[maxn], dis[maxn];

//d1、d2、dn分別為從1、2、n出發的最短路
ll d1[maxn], d2[maxn], dn[maxn], minn = 1e12;//不清楚?最好用long long吧……

void dijkstra(int s) {
	for (int i = 1; i <= n; i++) dis[i] = 0x3f3f3f3f;
	priority_queue< pair<int, int> > q;
	q.push(make_pair(0, s));
	dis[s] = 0;
	while (q.size()) {
		int u = q.top().second;
		q.pop();
		if (vis[u]) continue;
		vis[u] = 1;
		for (int i = head[u]; i; i = e[i].nxt) {
			int v = e[i].to;
			if (dis[v] > dis[u] + e[i].w) {
				dis[v] = dis[u] + e[i].w;
				q.push(make_pair(-dis[v], v));
			}
		}
	}
} 

int main() {
	cin >> a >> b >> c >> n >> m;
	if (c > a + b) c = a + b;
	for (int i = 1; i <= m; i++) {
		int u, v;
		cin >> u >> v;
		addEdge(u, v, 1);
		addEdge(v, u, 1);
	}
	//剩下的不想註釋了,大家看看解題技巧就明白了
	dijkstra(1);
	for (int i = 1; i <= n; i++) d1[i] = (ll)dis[i] * a;
	ms(vis);
	dijkstra(2);
	for (int i = 1; i <= n; i++) d2[i] = (ll)dis[i] * b;
	ms(vis);
	dijkstra(n);
	for (int i = 1; i <= n; i++) dn[i] = (ll)dis[i] * c;
	for (int i = 1; i <= n; i++) 
		if (d1[i] + d2[i] + dn[i] < minn) minn = d1[i] + d2[i] + dn[i];
	cout << minn;
	return 0;
}