分层图最短路复习

分层图可以来解决在图上的决策最短路问题。
按P4568 [JLOI2011]飞行路线这个题来说。
走每条边时可以有 K K K次让这条边免费的机会。
建图的方法是,原图先建好,针对 K K K次免费的机会,每次机会新建一层图,新建的每层图与原图相同,这里层就理解为上下排列着的,然后对于原图中的 u → v u\rightarrow v uv的边,在每相邻两层图之间连一条 u → v u\rightarrow v uv的边,层间的边边权为 0 0 0,例如下图 K = 1 K=1 K=1,为了简洁画的有向图。
分层图最短路复习_第1张图片
蓝色边就是层间的边,例如原图中有 1 → 2 1\rightarrow 2 12的边,在分层图中就从原图中的 1 1 1向下一层的 2 2 2建边,边权为 0 0 0
这样跑最短路时每垮一层图就表示用掉了一次免费的机会。
注意针对不同的题目最优策略不一定在第 K K K层图的 n n n号点,每层图都可能有最优策略,所以为了保险可以对每层图的 n n n点的值取一个最优。
这样连边会多连出很多边,所以注意计算加边数组的大小,而且每层图会多开点,还要注意计算点集大小
洛谷P4568 [JLOI2011]飞行路线
这个题边集是 50000 50000 50000的, K K K最多是 10 10 10,原图加两条边,其它层的图及层之间会加 4 4 4条边,每次最多加 42 42 42条边,所以边集要开到 ( 4 ∗ 10 + 2 ) ∗ 50000 = 2100000 (4*10+2)*50000=2100000 (410+2)50000=2100000
每层图要多开 n n n个点,所以点集是 10000 + 10000 ∗ 10 = 110000 10000+10000*10=110000 10000+1000010=110000的,注意都 + 10 +10 +10
下面的 s p f a spfa spfa用了 s l f slf slf优化

#include 
#define A 110010
#define B 2100010

using namespace std;
struct node {int next, to, w;}e[B];
int head[A], num;
void add(int fr, int to, int w) {
	e[++num].next = head[fr]; e[num].to = to;
	e[num].w = w; head[fr] = num;
}
int n, m, k, s, t, a, b, c, dis[A]; bool vis[A];
void spfa(int s) {
	memset(dis, 0x3f, sizeof dis); memset(vis, 0, sizeof vis);
	deque<int> q; dis[s] = 0; q.push_back(s);
	while (!q.empty()) {
		int fr = q.front(); q.pop_front(); vis[fr] = 0;
		for (int i = head[fr]; i; i = e[i].next) {
			int ca = e[i].to;
			if (dis[ca] > dis[fr] + e[i].w) {
				dis[ca] = dis[fr] + e[i].w;
				if (!vis[ca]) {
					vis[ca] = 1;
					if (q.empty() or dis[ca] > dis[q.front()]) q.push_back(ca);
					else q.push_front(ca);
				}
			}
		}
	}
}

int main(int argc, char const *argv[]) {
	cin >> n >> m >> k >> s >> t;
	for (int i = 1; i <= m; i++) {
		scanf("%d%d%d", &a, &b, &c);
		add(a, b, c); add(b, a, c);
		for (int j = 1; j <= k; j++) {
			add(a + (j - 1) * n, b + j * n, 0);
			add(b + (j - 1) * n, a + j * n, 0);
			add(a + j * n, b + j * n, c);
			add(b + j * n, a + j * n, c);
		}
	}
	spfa(s);
	for (int i = 0; i <= k; i++) ans = min(ans, dis[t + n * i]);
	cout << ans << endl;
}

你可能感兴趣的:(最短路,Luogu)