分层图学习笔记 & [JLOI2011]飞行路线题解
作者:互联网
分层图实际上就是把一个图复制好几份,代表一层一层,相邻的层之间的节点如果在原图有边就可以连边,同一层节点之间在原图有边也连边。
这里蓝边就是相邻层的边,黑边就是每层之间的边。原图就是 \((1,2),(1,3)\) 两条边。
Luogu P4568 [JLOI2011]飞行路线
给定一个图,每个图之间有边权,可以将 \(k\) 个边的边权改为 \(0\) ,求 \(S\) 到 \(T\) 的最短路。
其中 \(2\leq n\leq 10^4,1\leq m\leq 5\times 10^4,0\leq k\leq 10\)
可以把这个图分成 \(k\) 层的分层图,那么现在每个点和每条边代表什么意思呢?定义在第 \(i\) 层的节点为用了 \(i\) 次边权取 \(0\) 的节点,那么每个黑边在同一层图内走代表的就是没有使用边权取 \(0\), 而走蓝边就是代表把边权取 \(0\),然后走到下一层图(也就是代表使用了一次边权取 \(0\) 的操作)。
这个时候以第 \(0\) 层图的 \(s\) 为起点跑最短路,答案为每一层 \(t\) 的最短路的最小值。
\(\mathcal{Code}\)
#include<iostream>
#include<cstdio>
#include<queue>
#define pp std::pair<int, int>
#define mp std::make_pair
#define fir first
#define sec second
const int N = 10010;
const int M = 50010;
const int K = 21;
const int INF = 0x7fffffff;
inline int Min(int x, int y) { return x < y ? x : y; }
inline int read() {
int r = 0; bool w = 0; char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') w = 1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
r = (r << 3) + (r << 1) + (ch ^ 48);
ch = getchar();
}
return w ? ~r + 1 : r;
}
int n, m, k, s, t, ans = INF;
int dis[N * K];
bool vis[N * K];
//Edge
int head[N * K], ent;
struct Node {
int next, to, val;
}e[2 * ((2 + K) * M + K)];
inline void add(int x, int y, int z) {
e[++ent].to = y; e[ent].val = z; e[ent].next = head[x]; head[x] = ent;
}
std::priority_queue<pp>q;
void Dij() {
dis[s] = 0;
q.push(mp(-dis[s], s));
while(!q.empty()) {
int x = q.top().sec;
q.pop();
if(vis[x]) continue;
vis[x] = 1;
for(int i = head[x] ; i; i = e[i].next) {
int v = e[i].to;
if(dis[v] > dis[x] + e[i].val) {
dis[v] = dis[x] + e[i].val;
if(!vis[v]) q.push(mp(-dis[v], v));
}
}
}
}
signed main() {
n = read(); m = read(); k = read(); s = read(); t = read();
for(int i = 1; i <= m; ++i) {
int x = read(), y = read(), z = read();
add(x, y, z); add(y, x, z);
for(int j = 1; j <= k; ++j) {
add(x + (j - 1) * n, y + j * n, 0);
add(y + (j - 1) * n, x + j * n, 0);
add(x + j * n, y + j * n, z);
add(y + j * n, x + j * n, z);
}
}
for(int i = 0; i < n; ++i)
for(int j = 0; j <= k; ++j)
dis[i + j * n] = INF;
Dij();
for(int i = 0; i <= k; ++i) ans = Min(ans, dis[t + i * n]);
printf("%d\n", ans);
return 0;
}
标签:ch,const,JLOI2011,leq,int,题解,read,分层,dis 来源: https://www.cnblogs.com/do-while-true/p/13772996.html