P1401 城市
Posted init-神眷の樱花
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1401 城市相关的知识,希望对你有一定的参考价值。
题意
\\(n\\)个点,\\(m\\) 条边的无向图,求出 \\(t\\) 条路径,使路径中最长的边最小。
题解
看到最大的最小应该能马上想到二分答案。
于是我们差的就是一个 check 函数了。
不正确暴力
从点 \\(1\\) 出发遍历,将遍历的边及其反边打上标记,直至有 \\(t\\) 条路径为止。
这么一看感觉仿佛还可以,但是仔细想想,这样做不仅复杂度不优,反而得到的答案还并不正确。
如下图:
可能在第一次遍历的时候,上面那条路径与 \\(n\\) 连接的那条边,已经被打上标记了。而第二条路径其实可以走下面到达 \\(n\\)的,但是却把上面的那条占了,就只能跑出 \\(1\\) 条路径,但其实是 \\(2\\) 条的。这种情况根据你存边的顺序是有可能出现的。
所以这样的暴力不行。
并查集
使用并查集来维护也挺妙的,这是其它题解的思路,我没有打过,但是据他说有一个点卡不过,不知道加了按秩合并和编译优化之后能不能卡过。
网络流
这道题其实就考了一个最大流。
为什么这道题能用网络流来做呢?
其实一条路径就可以看做是从源点流出去的一个单位流量,因为残量网络是一个 DAG 图,所以满足了一条边只能经过一个方向的限制条件。
而我们将每条边的容量设为 \\(1\\) ,则相当于限制了一条边只能被一条路径经过。感性理解一下相当于是有 \\(t\\) 列火车从源点出发,向汇点开去,因为火车很长,它到达了汇点之后,尾巴还没有离开源点,而每条边只有一条轨道,于是每列火车都把它经过的边上的轨道都占了,就不会出现有两列火车同时在一条边的情况,所以这样的话,每条边是不会被重复经过的。
而对于长度不满足二分限制的边不加入残量网络中即可。
代码
#include<cstdio>
#include<ctype.h>
#include<cstring>
#include<iostream>
#include<queue>
const int N = 205, M = 4e4 + 5;
int head[N], nex[M << 1], to[M << 1], w[M << 1], edge[M << 1], n, m, siz = 1, t, ans;
long long L = 0, R = 1e9 + 7, mid;
inline void add(int u, int v, int W) {
nex[++siz] = head[u]; w[siz] = W;
to[siz] = v; head[u] = siz;
nex[++siz] = head[v]; w[siz] = W;
to[siz] = u; head[v] = siz;
}
int d[N], now[N]; std:: queue < int > q;
bool bfs(int s) {
memset(d, 0, sizeof(d));
while(!q.empty()) q.pop();
q.push(s); d[s] = 1; now[s] = head[s];
while(!q.empty()) {
int x = q.front(); q.pop();
for(int i = head[x]; i; i = nex[i])
if(edge[i] && !d[to[i]] && w[i] <= mid) {
q.push(to[i]);
now[to[i]] = head[to[i]];
d[to[i]] = d[x] + 1;
if(to[i] == n) return true;
}
}
return false;
}
int dinic(int x, int flow) {
if(x == n) return flow;
int res = flow, k, i;
for(i = now[x]; i && res; i = nex[i])
if(edge[i] && d[to[i]] == d[x] + 1 && w[i] <= mid) {
k = dinic(to[i], std::min(res, edge[i]));
if(!k) d[to[i]] = 0;
edge[i] -= k; edge[i ^ 1] += k;
res -= k;
}
now[x] = i;
return flow - res;
}
inline int read() {
int x = 0, f = 1, c = getchar();
for(; !isdigit(c); c = getchar())
if(c == \'-\')
f = -1;
for(; isdigit(c); c = getchar())
x = x * 10 + c - 48;
return x * f;
}
int main() {
n = read(), m = read(), t = read();
for(int i = 1; i <= m; i++) {
int u = read(), v = read(), W = read();
add(u, v, W);
}
while(L <= R) {
for(int i = 1; i <= siz; i++) edge[i] = 1;
mid = (L + R) >> 1;
int flow = 0, maxflow = 0;
while(bfs(1))
while(flow = dinic(1, 0x3f3f3f3f)) maxflow += flow;
if(maxflow >= t)
R = mid - 1, ans = mid;
else
L = mid + 1;
}
printf("%d\\n", ans);
return 0;
}```
以上是关于P1401 城市的主要内容,如果未能解决你的问题,请参考以下文章