图论-分层图学习笔记

在前几天模拟赛中第一次见,之前不太理解,今天大概搞明白些了。


个人理解分层图:图中的边在特定的时间可以变换。那就将各个时间根据当前不同的状态分层建图。

说白了就是存各边的不同状态。连边时,同一层的点可以相连,不同层的也可以连过去。

所以你就会发现分层图的难度在于建图,连边的时候要考虑不同层的怎么连。其他的就是套最短路的板子了。

另外需要特别注意的是存图的时候空间还是尽量开到 1e6 比较保险吧。因为实际上你在不同层中连边的话边数还是挺大的。

图不太好画,不妨自己往“分层”这方面想象一下。


模板题:

1.洛谷:P2939 [USACO09FEB] Revamping Trails G

建图的时候,建 k 层图分别存不同高速公路下的情况。

对于同一层内的边,算出对应的编号,边权不变,直接相连。

不同层内的边,从第 i 层连向第 i + 1 层,表示在这里又使用了一次高速公路让边权成为 0。

for(int i = 0; i <= k; i ++ ) add(i * n + x, i * n + y, z), add(i * n + y, i * n + x, z);
for(int i = 0; i < k; i ++ ) add(i * n + x, (i + 1) * n + y, 0), add(i * n + y, (i + 1) * n + x, 0);

最后对于每一层的节点,直接跑最短路就可。

#include<bits/stdc++.h>
using namespace std;
const int inf = 0x7fffffff;
const int N = 1e5 + 10;
const int M = 5e5 + 10;
int n, m, k;
int vis[N * 30], ans[N * 30];
int idx, head[N * 30], e[M * 30], w[M * 30], nxt[M * 30];
priority_queue<pair<int, int> > q;
void add(int x, int y, int z)
{
	e[++ idx] = y;
	w[idx] = z;
	nxt[idx] = head[x];
	head[x] = idx;
}
void dij()
{
	ans[1] = 0;
	q.push(make_pair(0, 1));
	while(q.size())
	{
		int x = q.top().second;
		q.pop();
		if(vis[x]) continue;
		vis[x] = 1;
		for(int i = head[x]; i; i = nxt[i])
		{
			if(ans[e[i]] > ans[x] + w[i])
			{
				ans[e[i]] = ans[x] + w[i];
				q.push(make_pair(-ans[e[i]], e[i]));
			}
		}
}
}
int main()
{
	scanf("%d%d%d", &n, &m, &k);
	while(m -- )
	{
		int x, y, z;
		scanf("%d%d%d", &x, &y, &z);
		for(int i = 0; i <= k; i ++ ) add(i * n + x, i * n + y, z), add(i * n + y, i * n + x, z);
		for(int i = 0; i < k; i ++ ) add(i * n + x, (i + 1) * n + y, 0), add(i * n + y, (i + 1) * n + x, 0);
	}
	for(int i = 1; i <= n * k + n; i ++ ) ans[i] = inf; 
	dij();
	int minn = inf;
	for(int i = 0; i <= k; i ++ ) minn = min(minn, ans[i * n + n]);
	printf("%d", minn);
}

细细琢磨,分层图真的越想越妙。


其他:三倍经验:

P4568 [JLOI2011] 飞行路线

P4822 [BJWC2012] 冻结

posted @ 2023-08-20 21:15  Moyyer_suiy  阅读(37)  评论(0编辑  收藏  举报