1. 程式人生 > >「BJWC 2012」凍結「分層圖+最短路」

「BJWC 2012」凍結「分層圖+最短路」

題目傳送門

題解

分層圖是一種不錯的技巧。對於這題來說,把圖複製成 k + 1 k+1 份,分別命名為 0 , 1

, . . . , k 0,1,...,k 層。第 i
i
層的含義就是已經用了 i i 次加速魔法。

讀入一條邊,每層連雙向邊,層與層之間,底層往上層連權值減半的單向邊,單向意味著只能上不能下。

然後答案就是跑最短路然後取 k + 1

k+1 層的 d i s ( n ) dis(n) 最小值.

#include <cstdio>
#include <vector>
#include <queue>
using namespace std;

#define P pair<int, int>
#define px first
#define py second

const int N = 5010;

int n, m, k;
int dis[N];
vector<P> G[N];

int Dijkstra() {
	priority_queue<P, vector<P>, greater<P> > Q;
	Q.push(P(dis[1] = 0, 1));
	for(int i = 2; i <= 5000; i ++) dis[i] = 1 << 29;
	for(; Q.size(); ) {
		P k = Q.top(); Q.pop(); int u = k.py;
		if(dis[u] < k.px) continue ;
		for(int i = 0; i < G[u].size(); i ++) {
			int v = G[u][i].px, w = G[u][i].py;
			if(dis[v] > dis[u] + w) {
				Q.push(P(dis[v] = dis[u] + w, v));
			}
		}
	}
	int ans = dis[n], base = n;
	for(int i = 1; i <= k; i ++, base += n)
		if(ans > dis[base + n]) ans = dis[base + n];
	return ans;
}

int main() {
	scanf("%d%d%d", &n, &m, &k);
	for(int i = 1, u, v, w; i <= m; i ++) {
		scanf("%d%d%d", &u, &v, &w);
		int base = 0;
		for(int j = 1; j <= k + 1; j ++, base += n) {
			G[base + u].push_back(P(base + v, w));
			G[base + v].push_back(P(base + u, w));
			if(base) {
				G[base - n + u].push_back(P(base + v, w >> 1));
				G[base - n + v].push_back(P(base + u, w >> 1));
			}
		}
	}
	
	printf("%d\n", Dijkstra());
	return 0;
}