洛谷P4568 [JLOI2011]飞行路线 (分层图最短路)

原题连接

题意
在m条航线中,可以选择k条路线免费,问从st到ed的最小花费是多少。

观察一下题目数据,n只有2e4而k只有10,因此n*(k+1)个点的时间复杂度也绰绰有余,这时就可以利用分层图的思想来写。

解题思路
将整个图想象成一个三维的立体空间,那么1到n个点排在第一层,n+1到2n的点排在第2层……依次类推,那么我们可以假设层与层之间的联系为免费的路线,每上一层相当于利用一次免费的机会,层之间当然是只上不下,因此如果有k次免费机会,那么就会有k+1层的图,最后答案肯定在每一层的st中找。

#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
const int M = 2000010;
int ne[2 * M], vi[2 * M], e[2 * M], h[N];
int tot, n, m, k, st, ed;
int dis[N], vis[N];

void add(int u, int v, int w) {
    
    
	e[tot] = v, vi[tot] = w, ne[tot] = h[u], h[u] = tot++;
}

struct node {
    
    
	int d, now;
	bool operator < (const node& x) const {
    
    
		return d > x.d;
	}
};

priority_queue<node> q;
void dijkstra(int s) {
    
    
	memset(dis, 0x3f, sizeof dis);
	dis[s] = 0;
	q.push(node{
    
     dis[st], st });
	while (q.size()) {
    
    
		node p = q.top();
		q.pop();
		int u = p.now;
		if (vis[u]) continue;
		vis[u] = 1;
		for (int i = h[u]; ~i; i = ne[i]) {
    
    
			int v = e[i];
			if (dis[v] > dis[u] + vi[i]) {
    
    
				dis[v] = dis[u] + vi[i];
				if (!vis[v]) {
    
    
					q.push(node{
    
     dis[v], v });
				}
			}
		}
	}
}

int main() {
    
    
	cin >> n >> m >> k;
	cin >> st >> ed;
	st++, ed++;
	memset(h, -1, sizeof h);
	for (int i = 0; i < m; i++) {
    
    
		int x, y, z;
		cin >> x >> y >> z;
		x++, y++;
		add(x, y, z), add(y, x, z);
		for (int j = 1; j <= k; j++) {
    
    
			add(x + j * n, y + j * n, z);
			add(y + j * n, x + j * n, z);
			add(x + (j - 1) * n, y + j * n, 0);
			add(y + (j - 1) * n, x + j * n, 0);
		}
	}
	
	dijkstra(st);
	int res = 999999999;
	for (int i = ed; i <= (k + 1) * n; i += n) res = min(res, dis[i]);
	cout << res << endl;
}

猜你喜欢

转载自blog.csdn.net/kaka03200/article/details/106529918
今日推荐