POJ 3084 Panic Room(最大流最小割)
Description
You are the lead programmer for the Securitron 9042, the latest and greatest in home security software from Jellern Inc. (Motto: We secure your stuff so YOU can't even get to it). The software is designed to "secure" a room; it does this by determining the minimum number of locks it has to perform to prevent access to a given room from one or more other rooms. Each door connects two rooms and has a single control panel that will unlock it. This control panel is accessible from only one side of the door. So, for example, if the layout of a house looked like this: with rooms numbered 0-6 and control panels marked with the letters "CP" (each next to the door it can unlock and in the room that it is accessible from), then one could say that the minimum number of locks to perform to secure room 2 from room 1 is two; one has to lock the door between room 2 and room 1 and the door between room 3 and room 1. Note that it is impossible to secure room 2 from room 3, since one would always be able to use the control panel in room 3 that unlocks the door between room 3 and room 2.
Input
Input to this problem will begin with a line containing a single integer x indicating the number of datasets. Each data set consists of two components:
- Start line – a single line "m n" (1 <=m<= 20; 0 <=n<= 19) where m indicates the number of rooms in the house and n indicates the room to secure (the panic room).
- Room list – a series of m lines. Each line lists, for a single room, whether there is an intruder in that room ("I" for intruder, "NI" for no intruder), a count of doors c (0 <= c <= 20) that lead to other rooms and have a control panel in this room, and a list of rooms that those doors lead to. For example, if room 3 had no intruder, and doors to rooms 1 and 2, and each of those doors' control panels were accessible from room 3 (as is the case in the above layout), the line for room 3 would read "NI 2 1 2". The first line in the list represents room 0. The second line represents room 1, and so on until the last line, which represents room m - 1. On each line, the rooms are always listed in ascending order. It is possible for rooms to be connected by multiple doors and for there to be more than one intruder!
Output
For each dataset, output the fewest number of locks to perform to secure the panic room from all the intruders. If it is impossible to secure the panic room from all the intruders, output "PANIC ROOM BREACH". Assume that all doors start out unlocked and there will not be an intruder in the panic room.
题目大意:有n个房间,若干扇门,门是单向的,只能从一边上锁(如一道门连接a→b,任何时刻都能从a走到b,但上了锁之后就不能从b走到a了)。现在有些坏蛋入侵了一些房间,你不想让他们来到你的房间,问最少要锁上多少扇门,若全锁上都木有用……就……
思路:新建一个源点S,从S到坏蛋们入侵的房间连一条容量为无穷大的边,对每扇门a→b,连一条边a→b容量为无穷大,连b→a容量为1。若最大流≥无穷大(我是增广到一条容量为无穷大的路径直接退出),则无解(死定啦死定啦),否则最大流为答案。实则为求最小割,好像不需要解释了挺好理解的……
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 using namespace std; 6 7 const int MAXN = 25; 8 const int MAXE = 3010; 9 const int INF = 0x3fff3fff; 10 11 struct SAP { 12 int head[MAXN], dis[MAXN], pre[MAXN], cur[MAXN], gap[MAXN]; 13 int to[MAXE], next[MAXE], flow[MAXE]; 14 int n, st, ed, ecnt; 15 16 void init() { 17 memset(head, 0, sizeof(head)); 18 ecnt = 2; 19 } 20 21 void add_edge(int u, int v, int c) { 22 to[ecnt] = v; flow[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++; 23 to[ecnt] = u; flow[ecnt] = 0; next[ecnt] = head[v]; head[v] = ecnt++; 24 //printf("%d->%d flow = %d\n", u, v, c); 25 } 26 27 void bfs() { 28 memset(dis, 0x3f, sizeof(dis)); 29 queue<int> que; que.push(ed); 30 dis[ed] = 0; 31 while(!que.empty()) { 32 int u = que.front(); que.pop(); 33 ++gap[dis[u]]; 34 for(int p = head[u]; p; p = next[p]) { 35 int &v = to[p]; 36 if(flow[p ^ 1] && dis[v] > n) { 37 dis[v] = dis[u] + 1; 38 que.push(v); 39 } 40 } 41 } 42 } 43 44 int Max_flow(int ss, int tt, int nn) { 45 st = ss; ed = tt; n = nn; 46 int ans = 0, minFlow = INF, u; 47 for(int i = 0; i <= n; ++i) { 48 cur[i] = head[i]; 49 gap[i] = 0; 50 } 51 u = pre[st] = st; 52 bfs(); 53 while(dis[st] < n) { 54 bool flag = false; 55 for(int &p = cur[u]; p; p = next[p]) { 56 int &v = to[p]; 57 if(flow[p] && dis[u] == dis[v] + 1) { 58 flag = true; 59 minFlow = min(minFlow, flow[p]); 60 pre[v] = u; 61 u = v; 62 if(u == ed) { 63 if(minFlow == INF) return INF;//no ans 64 ans += minFlow; 65 while(u != st) { 66 u = pre[u]; 67 flow[cur[u]] -= minFlow; 68 flow[cur[u] ^ 1] += minFlow; 69 } 70 minFlow = INF; 71 } 72 break; 73 } 74 } 75 if(flag) continue; 76 int minDis = n - 1; 77 for(int p = head[u]; p; p = next[p]) { 78 int &v = to[p]; 79 if(flow[p] && minDis > dis[v]) { 80 minDis = dis[v]; 81 cur[u] = p; 82 } 83 } 84 if(--gap[dis[u]] == 0) break; 85 gap[dis[u] = minDis + 1]++; 86 u = pre[u]; 87 } 88 return ans; 89 } 90 } G; 91 92 char s[5]; 93 int n, ss, tt, T, c, x; 94 95 int main() { 96 scanf("%d", &T); 97 while(T--) { 98 scanf("%d%d", &n, &tt); 99 ss = n; 100 G.init(); 101 for(int i = 0; i < n; ++i) { 102 scanf("%s%d", s, &c); 103 while(c--) { 104 scanf("%d", &x); 105 G.add_edge(i, x, INF); 106 G.add_edge(x, i, 1); 107 } 108 if(s[0] == 'I') G.add_edge(ss, i, INF); 109 } 110 int ans = G.Max_flow(ss, tt, ss); 111 if(ans == INF) puts("PANIC ROOM BREACH"); 112 else printf("%d\n", ans); 113 } 114 }