在前几天模拟赛中第一次见,之前不太理解,今天大概搞明白些了。
个人理解分层图:图中的边在特定的时间可以变换。那就将各个时间根据当前不同的状态分层建图。
说白了就是存各边的不同状态。连边时,同一层的点可以相连,不同层的也可以连过去。
所以你就会发现分层图的难度在于建图,连边的时候要考虑不同层的怎么连。其他的就是套最短路的板子了。
另外需要特别注意的是存图的时候空间还是尽量开到 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);
}
细细琢磨,分层图真的越想越妙。
其他:三倍经验:
标签:图论,d%,idx,int,30,笔记,分层,ans From: https://www.cnblogs.com/Moyyer-suiy/p/17644604.html