网络流建模专题
struct DI {
ll n, m, S, T;
ll h[N], ne[M], to[M], f[M], idx;
void add(ll u, ll v, ll w) {
ne[idx] = h[u], to[idx] = v, f[idx] = w, h[u] = idx++;
ne[idx] = h[v], to[idx] = u, f[idx] = 0, h[v] = idx++;
}
queue<ll> q;
ll d[N];
ll cur[N];
void init() {
for (int i = 0; i <= idx; i ++)h[i] = -1;
idx = 0;
}
bool bfs() {
while (!q.empty()) q.pop();
q.push(S);
memset(d, -1, sizeof d); // d数组是深度,防止绕进环中去。
d[S] = 0;
cur[S] = h[S]; //必然第一个弧就是,但是容易忘。
while (!q.empty()) {
auto u = q.front();
q.pop();
for (ll i = h[u]; ~i; i = ne[i]) {
ll v = to[i];
if (f[i] && d[v] == -1) { //找增广路,所以必须f[i] > 0
d[v] = 1 + d[u];
cur[v] = h[v]; //只会遍历一次。
if (v == T) return 1;
q.push(v);
}
}
}
return 0;
}
ll dfs(ll u, ll limit) {
if (u == T) return limit; //容易忘。终点直接返回
ll flow = 0; //点流向后面的。
for (ll i = cur[u]; ~i && flow < limit;
i = ne[i]) { //从当前弧开始,如果之前
ll v = to[i];
cur[u] = i; //回溯到u点之前,然后又到了u点,没必要从头开始了。
if (d[v] == d[u] + 1 && f[i]) { // d是按照层数走,f必须大于0。
ll t = dfs(v, min(f[i], limit - flow)); // t是走向出去的流量。
if (t <= 0) d[v] = -1; //一滴也没有了,点就可以删掉了。
f[i] -= t;
f[i ^ 1] += t; //更新残留网络。
flow += t; //当前总的流向后面的加上当前v流向后面的。
}
}
return flow;
}
ll dinic() {
ll ret = 0, flow;
while (bfs()) {
while (flow = dfs(S, inf)) ret += flow;
}
//init();
return ret;
}
void makemap() {
init();
scanf("%d", &n);
S = 0;
T = N-1;
for (int i = 1; i <= n * 2; i ++)add(S, i, 1);
for (int i = 1; i <= 2 * n; i ++) {
int u, v;
scanf("%d%d", &u, &v);
u += 3*n;
v += 3*n;
add(i, u, 1);
add(i, v, 1);
}
for (int i = 1; i <= n; i ++) {
add(i + 3 * n, T, 2);
}
}
}dinic;
-
P2754 [CTSC1999]家园 / 星际转移问题
按照时间建立分层图建模,注意飞船转移的时候当飞船返回也要建立一条边。 -
P2526 [SHOI2001]小狗散步
发现是一个二分图的关键在于,是否能找到他们是一一对应的关系,这个小狗他每次只出去一个经典,就很无语。 -
P2057 [SHOI2007]善意的投票 / [JLOI2010]冠军调查
冲突模型最小割,睡觉不睡觉一定会分成两个集合,然后好朋友们之间流量是1,所以建立双向边跑最大流得到最小割,就是把他们分成睡觉和不睡觉最小冲突的分法。 -
[TJOI2013]攻击装置
经中之典的建模,一些关系不能冲突,求互不冲突最大数量,最大独立集,就是所有点数量减去最大匹配。 -
Penguins LightOJ - 1154-vj
拆点,会发现,跳跃之间流量要赋成正无穷,所以如果要限制跳跃次数,就应该把一个冰拆成两层,用 \(limit\) 跳跃次数作为流量从底层跳到高层,然后再跳向其他的底层,然后枚举汇点,注意汇点连接的是底层 -
P1251 餐巾计划问题
如果题目中要求每天都要满足条件,类似的,那么就可以设为将每个要满足的和汇点连边,容量设为应满足的条件。 -
P1345 [USACO5.4]奶牛的电信Telecowmunication
经中之典最小割,如果要求删去最小数量边,好求。如果要求删去数量的点,那么就要使得每个点拆成出度和入度,之间的流量限制为 \(1\), 然后就可以出度点连接入度点了,权值设为正无穷,注意不要另设一个源汇点,因为如果求最小割,还是点之间的,想想就知道不行。 -
HDU 3605
经中之典状态压缩,\(n\) 太多了没想到 \(m\) 很小,然后就可以多记录状态了。 -
P1361 小M的作物
经中之典最小割模型,种两种地方,有不同的收获,并且组合种某种地方也有格外收获,会发现如果从 \(A\) 到 \(B\) 就是最小割模型。 -
P4843 清理雪道
发现,题目要求每条边必须走过,那么所以一定是所有边流量下界为1,然后流量上界为inf,所以就是建好无源汇上下界可行流,然后搞有源汇上下界最小流。 -
P4043 [AHOI2014/JSOI2014]支线剧情
经典上下界最小费用可行流,就是定好上下界和费用,然后返回的时候连反向正无穷边。注意,得到新图后,最小费用是先计算好下界流量乘以相应费用,然后在计算附加图的最小费用。 -
P3980 [NOI2008] 志愿者招募
经典上下界最小费用可行流,但是这个没算原图的流量下界乘费用,因为反边的流量下界为0。 -
P4311 士兵占领
经典网格图,然后就是最开始的想法是,作为无源汇可行流来解,即只有行的入点出点,列的入点出点,网格上的点,但是这样边和点数量过多。可是如果想象成类似二分图,把行和列拿出来,然后虚拟源点连接行,然后列连接虚拟汇点,然后行和列之间就可以连边,规定好流量上下界即可解决。 -
P4553 80人环游世界
简单上下界费用流建模。景点国家的出入点决定到这个国家几个人,然后源点连出流量为人数的点到一个小源点,然后从小源点连向每个景点,然后景点之间机票可以连边,从景点的出点连向景点的入点。 -
P1344 [USACO4.4]追查坏牛奶Pollutant Control
最小割神仙题目,不仅让求最小的割,并且求得的是边的割集的最小权值和,一种神仙做法是,将每个边权转化为, \(w = x \times C + y\),其中 \(\sum y < C\),所以就是 \(y\) 就是1,意义是一条边,然后最后求得答案,割的数量就是 \(maxflow \mod C\),最小边权和就是 \(\frac{maxflow}{C}\).