bzoj2502 清理雪道
2502: 清理雪道
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1279 Solved: 690
[Submit][Status][Discuss]
Description
滑雪场坐落在FJ省西北部的若干座山上。
从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向。
你的团队负责每周定时清理雪道。你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部。从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道。
由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务。
Input
输入文件的第一行包含一个整数n (2 <= n <= 100) – 代表滑雪场的地点的数量。接下来的n行,描述1~n号地点出发的斜坡,第i行的第一个数为mi (0 <= mi < n) ,后面共有mi个整数,由空格隔开,每个整数aij互不相同,代表从地点i下降到地点aij的斜坡。每个地点至少有一个斜坡与之相连。
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
Source
分析:题目就是要求把所有边都走一次的最小流.
很容易想到无源汇的上下界最小流. 添加一个源点S和一个汇点T,S向每个点连容量为inf的边,每个点向T连容量为inf的边.这样就转化成了有源汇的上下界最小流.
套用模板:1.每条边的起点u向终点v连边,容量为inf(因为上界是inf,下界是1,实际上是inf - 1,和inf没有区别).
2.S向每个点连容量为inf的边,每个点向T连容量为inf的边.
3.超级源点SS向每个点连容量为du[i]的边(如果du[i] > 0),每个点向超级汇点TT连容量为-du[i]的边(如果du[i] < 0).
4.先求出SS到TT的最大流,再连边T --> S,容量为inf,再跑一次从SS到TT的最大流. TT到SS这条边跑过的流量即为答案.
一个问题:为什么不拆点建图呢?(把一个点拆成入点和出点两个点).
因为人可以随时停下来,并且滑的过程可能会经过许多点,而不是只经过两个点,不好建图.
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 30010,inf = 0x7fffffff; int n,S,T,SS,TT,head[maxn],to[maxn],nextt[maxn],w[maxn],tot = 2; int du[maxn],d[maxn]; void add(int x,int y,int z) { w[tot] = z; to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; w[tot] = 0; to[tot] = x; nextt[tot] = head[y]; head[y] = tot++; } bool bfs() { memset(d,-1,sizeof(d)); queue <int> q; q.push(SS); d[SS] = 0; while (!q.empty()) { int u = q.front(); q.pop(); if (u == TT) return true; for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (w[i] && d[v] == -1) { d[v] = d[u] + 1; q.push(v); } } } return false; } int dfs(int u,int f) { if (u == TT) return f; int res = 0; for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (w[i] && d[v] == d[u] + 1) { int temp = dfs(v,min(f - res,w[i])); w[i] -= temp; w[i ^ 1] += temp; res += temp; if (res == f) return res; } } if (!res) d[u] = -1; return res; } void dinic() { while (bfs()) dfs(SS,inf); } int main() { scanf("%d",&n); S = n + 1; T = S + 1; SS = T + 1; TT = SS + 1; for (int i = 1; i <= n; i++) { int num; scanf("%d",&num); for (int j = 1; j <= num; j++) { int x; scanf("%d",&x); add(i,x,inf); du[i]--; du[x]++; } add(S,i,inf); add(i,T,inf); } for (int i = 1; i <= T; i++) { if (du[i] > 0) add(SS,i,du[i]); if (du[i] < 0) add(i,TT,-du[i]); } dinic(); add(T,S,inf); dinic(); printf("%d\n",w[tot - 1]); return 0; }