ZOJ-2788 Panic Room 【最小割】

Introduction

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:

1. Start line �C 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).
2. Room list �C 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.

Sample Input

3
7 2
NI 0
I 3 0 4 5
NI 2 1 6
NI 2 1 2
NI 0
NI 0
NI 0
7 2
I 0
NI 3 0 4 5
NI 2 1 6
I 2 1 2
NI 0
NI 0
NI 0
4 3
I 0
NI 1 2
NI 1 0
NI 4 1 1 2 2

Sample Output

2
PANIC ROOM BREACH
1



题解:

网络流建模求最小割,我们设一个源点s,有入侵者的点u就加一条弧s->u容量为inf,因为求最小割我们希望有入侵者的点都和s相连而不能和汇点相连,设inf在有解的情况下这条弧是不会被收进最小割的,其他的房间关系,u房间能打开门到v,我们设弧u->v容量为inf,因为这个方向锁不住,我们也不能让它存在于最小割中。最重要就是设反向弧v->u的容量为1,因为这个方向我们可以关一扇门隔断。建模之后就是求最小割(利用最大流最小割定理求最大流),有解情况下最小割收录的弧就是要关的门数,这时候这个s-t割的所有有入侵者的点一定是在s部分的,于是就将所有入侵者挡住了,如果无解,则必定最小割中收录了inf的弧,这时候这条弧实际上是割不断两点的。

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define INF 0x3f3f3f3f
  4 #define M(a, b) memset(a, b, sizeof(a))
  5 const int N = 20 + 5;
  6 struct Edge {
  7     int from, to, cap, flow;
  8 };
  9 
 10 struct Dinic {
 11     int n, m, s, t;
 12     vector<Edge> edges;
 13     vector<int> G[N];
 14     bool vis[N];
 15     int d[N], cur[N];
 16 
 17     void init(int n) {
 18         for (int i = 0; i <= n; ++i) G[i].clear();
 19         edges.clear();
 20     }
 21 
 22     void AddEdge(int from, int to, int cap) {
 23         edges.push_back((Edge){from, to, cap, 0});
 24         edges.push_back((Edge){to, from, 0, 0});
 25         m = edges.size();
 26         G[from].push_back(m-2); G[to].push_back(m-1);
 27     }
 28 
 29     bool bfs() {
 30         M(vis, 0);
 31         queue<int> q;
 32         q.push(s);
 33         d[s] = 0; vis[s] = 1;
 34         while (!q.empty()) {
 35             int x = q.front(); q.pop();
 36             for (int i = 0; i < G[x].size(); ++i) {
 37                 Edge &e = edges[G[x][i]];
 38                 if (!vis[e.to] && e.cap > e.flow) {
 39                     vis[e.to] = 1;
 40                     d[e.to] = d[x] + 1;
 41                     q.push(e.to);
 42                 }
 43             }
 44         }
 45         return vis[t];
 46     }
 47 
 48     int dfs(int x, int a) {
 49         if (x == t || a == 0) return a;
 50         int flow = 0, f;
 51         for (int &i = cur[x]; i < G[x].size(); ++i) {
 52             Edge &e = edges[G[x][i]];
 53             if (d[e.to] == d[x] + 1 && (f = dfs(e.to, min(a, e.cap-e.flow))) > 0) {
 54                 e.flow += f;
 55                 edges[G[x][i]^1].flow -= f;
 56                 flow += f; a -= f;
 57                 if (a == 0) break;
 58             }
 59         }
 60         return flow;
 61     }
 62 
 63     int Maxflow(int s, int t) {
 64         this->s = s; this->t = t;
 65         int flow = 0;
 66         while (bfs()) {
 67             M(cur, 0);
 68             flow += dfs(s, INF);
 69         }
 70         return flow;
 71     }
 72 
 73 }solver;
 74 
 75 
 76 int main() {
 77     int T, n, t;
 78     scanf("%d", &T);
 79     while (T--) {
 80         scanf("%d%d", &n, &t);
 81         solver.init(n);
 82         int v, s = n, m;
 83         char str[5];
 84         for (int u = 0; u < n; ++u) {
 85             scanf("%s", str);
 86             if (str[0] == 'I') {
 87                 solver.AddEdge(s, u, INF);
 88             }
 89             scanf("%d", &m);
 90             while (m--) {
 91                 scanf("%d", &v);
 92                 solver.AddEdge(u, v, INF);
 93                 solver.AddEdge(v, u, 1);
 94             }
 95         }
 96         int ans = solver.Maxflow(s, t);
 97         if (ans >= INF) printf("PANIC ROOM BREACH
");
 98         else printf("%d
", ans);
 99     }
100 
101     return 0;
102 }
原文地址:https://www.cnblogs.com/robin1998/p/6758925.html