bzoj2502【有上下界的最大流】
2502: 清理雪道
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 834 Solved: 442
[Submit][Status][Discuss]
Description
滑雪场坐落在FJ省西北部的若干座山上。
从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向。
你的团队负责每周定时清理雪道。你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部。从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道。
由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务。
Input
Output
输出文件的第一行是一个整数k – 直升飞机的最少飞行次数。
Sample Input
8
1 3
1 7
2 4 5
1 8
1 8
0
2 6 5
0
1 3
1 7
2 4 5
1 8
1 8
0
2 6 5
0
Sample Output
4
HINT
Source
这道题网上所有的解答都是最小流 但是我搞到了一个有上下界的最大流的做法 不知道对不对 求大家来批判
原始建图:
首先设立虚拟源汇S、T,S向每个节点u连一条容量为1的边,下界为0。因为每个点最多空降一次。
每个出度为0的点向汇点连边,容量为+∞
设fx=S -> u 的流量 fe=u -> v 的流量 fE=u->t的流量
设对于点u,流进来的流量为fe1,流出为fe2
由流量平衡得:fe1+fx=fe2+fE
设gx=出度-fx(fx<=出度) ->gx>=0(这里因为从这里滑到终点的次数不会比出度多)
gE=入度-fE(fE<=入度)->gE>=0(同上)
ge1=fe1-1 ge2=fe2-1
由fe1+fe=fe2+fE推出ge1+1+出度-gx=ge2+1+入度-fE
ge1+入度+出度-gx=ge2+入度+出度-gE
ge1-gx=ge2-gE ge1+gE=ge2+gx
这个东西满足流量平衡 然后我们跑一遍有上下界的最大流就可以了。
代码未填坑
这是最小流的代码
#include<bits/stdc++.h> using namespace std; const int N = 1010, inf = 1 << 29; struct edge { int nxt, to, f; } e[100010]; int n, cnt = 1, SS, TT, ans, T, tot; int head[N], d[N], q[N], in[N], iter[N]; void link(int u, int v, int f) { e[++cnt].nxt = head[u]; head[u] = cnt; e[cnt].to = v; e[cnt].f = f; } void ins(int u, int v, int f) { link(u, v, f); link(v, u, 0); } bool bfs() { int l = 1, r = 0; memset(d, 0, sizeof(d)); q[++r] = SS; d[SS] = 1; while(l <= r) { int u = q[l++]; for(int i = head[u]; i; i = e[i].nxt) if(e[i].f && !d[e[i].to]) { d[e[i].to] = d[u] + 1; q[++r] = e[i].to; } } return d[TT] > 0; } int dfs(int u, int delta) { if(u == TT) return delta; int ret = 0; for(int &i = iter[u]; i && delta; i = e[i].nxt) if(e[i].f && d[e[i].to] == d[u] + 1) { int x = dfs(e[i].to, min(delta, e[i].f)); e[i].f -= x; e[i ^ 1].f += x; delta -= x; ret += x; } return ret; } void dinic() { while(bfs()) { for(int i = 0; i <= TT; ++i) iter[i] = head[i]; ans += dfs(SS, inf); } } int main() { scanf("%d", &n); T = n + 1; SS = n + 2; TT = n + 3; for(int i = 1; i <= n; ++i) { int m; ins(0, i, inf); scanf("%d", &m); if(!m) ins(i, T, inf); for(int j = 1; j <= m; ++j) { int u; scanf("%d", &u); ++tot; --in[i]; ++in[u]; ins(i, u, inf); } } for(int i = 0; i <= T; ++i) { if(in[i] > 0) ins(SS, i, in[i]); else ins(i, TT, -in[i]); } dinic(); ins(n + 1, 0, inf); dinic(); printf("%d\n", inf - e[cnt ^ 1].f); return 0; }