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.
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
题意:如果房间a的机关能打开b,则a->b.有些房间有盗贼,因为游戏开始时,房间的门都开的,为了防止盗贼能到达某个秘密性房间,必须将一些房间的门关掉。
求:最少要关掉多少门。
分析:图的边连通度。
从盗贼为起点:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#define Min(a, b) (a) < (b) ? a : b
#define Max(a, b) (a) > (b) ? a : b
using namespace std;
const int MAXN = 1005;
const int MAXM = 210000;
const int INF = 1100000;
struct Edge
{
int st, ed;
int next;
int flow;
int cap;
}edge[MAXM];
int head[MAXN], level[MAXN], que[MAXN], E;
void add(int u, int v, int w)
{
//printf("add %d %d %d\n", u, v, w);
edge[E].flow = 0;
edge[E].cap = w;
edge[E].st = u;
edge[E].ed = v;
edge[E].next = head[u];
head[u] = E++;
edge[E].flow = 0;
edge[E].cap = 0;
edge[E].st = v;
edge[E].ed = u;
edge[E].next = head[v];
head[v] = E++;
}
int dinic_bfs(int src, int dest, int ver)
{
int i, j;
for (i = 0; i <= ver; i++)
{
level[i] = -1;
}
int rear = 1;
que[0] = src; level[src] = 0;
for(i = 0; i < rear; i++)
{
for(j = head[que[i]]; j != -1; j = edge[j].next)
{
if(level[edge[j].ed] == -1 && edge[j].cap > edge[j].flow)
{
level[edge[j].ed] = level[que[i]]+1;
que[rear++] = edge[j].ed;
}
}
}
return level[dest] >= 0;
}
int dinic_dfs(int src, int dest, int ver)
{
int stk[MAXN], top = 0;
int ret = 0, cur, ptr, pre[MAXN], minf, i;
int del[MAXN];
for (i = 0; i <= ver; i++)
{
del[i] = 0;
}
stk[top++] = src;
pre[src] = src;
cur = src;
while(top)
{
while(cur != dest && top)
{
for(i = head[cur]; i != -1; i = edge[i].next)
{
if(level[edge[i].ed] == level[cur] + 1 && edge[i].cap > edge[i].flow && !del[edge[i].ed])
{
stk[top++] = edge[i].ed;
cur = edge[i].ed;
pre[edge[i].ed] = i;
break;
}
}
if(i == -1)
{
del[cur] = 1;
top--;
if(top) cur = stk[top-1];
}
}
if(cur == dest)
{
minf = INF;
while(cur != src)
{
cur = pre[cur];
if(edge[cur].cap - edge[cur].flow < minf) minf = edge[cur].cap - edge[cur].flow;
cur = edge[cur].st;
}
cur = dest;
while(cur != src)
{
cur = pre[cur];
edge[cur].flow += minf;
edge[cur^1].flow -= minf;
if(edge[cur].cap - edge[cur].flow == 0)
{
ptr = edge[cur].st;
}
cur = edge[cur].st;
}
while(top > 0&& stk[top-1] != ptr) top--;
if(top) cur = stk[top-1];
ret += minf;
}
}
return ret;
}
int Dinic(int src, int dest, int ver)
{
int ret = 0, t;
while(dinic_bfs(src, dest, ver))
{
t = dinic_dfs(src, dest, ver);
if(t) ret += t;
else break;
}
return ret;
}
int main()
{
int ca, n, m, s, t, ver, i, j, k, v;
scanf("%d", &ca);
char ch[3];
while (ca--)
{
scanf("%d%d", &n, &m);
E = 0;
s = n, t = n + 1, ver = t + 1;
for (i = 0; i <= ver; i++)
{
head[i] = -1;
}
for (i = 0; i < n; i++)
{
scanf("%s%d", ch, &k);
if (strcmp(ch, "I") == 0)
{
add(s, i, INF);//从盗贼为出发点
}
while (k--)
{
scanf("%d", &v);
add(i, v, INF);//表示通过i能直接打开v
add(v, i, 1);
}
}
add(m, t, INF);
int ans;
ans = Dinic(s, t, ver);
if (ans >= INF)
{
printf("PANIC ROOM BREACH\n");
}
else
{
printf("%d\n", ans);
}
}
return 0;
}
/*
100
4 2
I 0
NI 1 0
NI 1 1
NI 2 2 1
5 2
I 0
NI 1 0
NI 1 1
NI 3 2 1 4
I 0
5 2
I 0
I 1 0
I 1 1
I 3 2 1 4
I 0
1 0
NI 0
1 0
I 0
2 1
I 0
NI 1 0
2 1
I 0
NI 3 0 0 0
3 2
I 0
NI 2 0 2
NI 1 1
2 1
I 1 1
NI 1 0
*/
以秘密房间为起点,这比较麻烦,如果某个房间能到秘密房间。则也必须从源向它连个inf的容量。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#define Min(a, b) (a) < (b) ? a : b
#define Max(a, b) (a) > (b) ? a : b
using namespace std;
const int MAXN = 1005;
const int MAXM = 210000;
const int INF = 1100000;
struct Edge
{
int st, ed;
int next;
int flow;
int cap;
}edge[MAXM];
int head[MAXN], level[MAXN], que[MAXN], E;
void add(int u, int v, int w)
{
//printf("add %d %d %d\n", u, v, w);
edge[E].flow = 0;
edge[E].cap = w;
edge[E].st = u;
edge[E].ed = v;
edge[E].next = head[u];
head[u] = E++;
edge[E].flow = 0;
edge[E].cap = 0;
edge[E].st = v;
edge[E].ed = u;
edge[E].next = head[v];
head[v] = E++;
}
int dinic_bfs(int src, int dest, int ver)
{
int i, j;
for (i = 0; i <= ver; i++)
{
level[i] = -1;
}
int rear = 1;
que[0] = src; level[src] = 0;
for(i = 0; i < rear; i++)
{
for(j = head[que[i]]; j != -1; j = edge[j].next)
{
if(level[edge[j].ed] == -1 && edge[j].cap > edge[j].flow)
{
level[edge[j].ed] = level[que[i]]+1;
que[rear++] = edge[j].ed;
}
}
}
return level[dest] >= 0;
}
int dinic_dfs(int src, int dest, int ver)
{
int stk[MAXN], top = 0;
int ret = 0, cur, ptr, pre[MAXN], minf, i;
int del[MAXN];
for (i = 0; i <= ver; i++)
{
del[i] = 0;
}
stk[top++] = src;
pre[src] = src;
cur = src;
while(top)
{
while(cur != dest && top)
{
for(i = head[cur]; i != -1; i = edge[i].next)
{
if(level[edge[i].ed] == level[cur] + 1 && edge[i].cap > edge[i].flow && !del[edge[i].ed])
{
stk[top++] = edge[i].ed;
cur = edge[i].ed;
pre[edge[i].ed] = i;
break;
}
}
if(i == -1)
{
del[cur] = 1;
top--;
if(top) cur = stk[top-1];
}
}
if(cur == dest)
{
minf = INF;
while(cur != src)
{
cur = pre[cur];
if(edge[cur].cap - edge[cur].flow < minf) minf = edge[cur].cap - edge[cur].flow;
cur = edge[cur].st;
}
cur = dest;
while(cur != src)
{
cur = pre[cur];
edge[cur].flow += minf;
edge[cur^1].flow -= minf;
if(edge[cur].cap - edge[cur].flow == 0)
{
ptr = edge[cur].st;
}
cur = edge[cur].st;
}
while(top > 0&& stk[top-1] != ptr) top--;
if(top) cur = stk[top-1];
ret += minf;
}
}
return ret;
}
int Dinic(int src, int dest, int ver)
{
int ret = 0, t;
while(dinic_bfs(src, dest, ver))
{
t = dinic_dfs(src, dest, ver);
if(t) ret += t;
else break;
}
return ret;
}
struct T
{
int v, next;
}fn[1000];
int g[50], th, flag[50];
void insert(int u, int v)
{
fn[th].v = v, fn[th].next = g[u], g[u] = th++;
}
void dfs(int u)
{
flag[u] = 1;
int i;
for (i = g[u]; i != -1; i = fn[i].next)
{
if (!flag[fn[i].v])
{
dfs(fn[i].v);
}
}
}
int main()
{
int ca, n, m, s, t, ver, i, j, k, v;
scanf("%d", &ca);
char ch[3];
while (ca--)
{
scanf("%d%d", &n, &m);
E = 0;
th = 0;
s = n, t = n + 1, ver = t + 1;
for (i = 0; i < n; i++)
{
flag[i] = 0;
g[i] = -1;
}
for (i = 0; i <= ver; i++)
{
head[i] = -1;
}
for (i = 0; i < n; i++)
{
scanf("%s%d", ch, &k);
if (strcmp(ch, "I") == 0)
{
add(i, t, INF);
}
while (k--)
{
scanf("%d", &v);
add(i, v, 1);
add(v, i, INF);
insert(v, i);
}
}
dfs(m);
for (i = 0; i < n; i++)
{
if (flag[i] == 1)
{
add(s, i, INF);
}
}
int ans;
ans = Dinic(s, t, ver);
if (ans >= INF)
{
printf("PANIC ROOM BREACH\n");
}
else
{
printf("%d\n", ans);
}
}
return 0;
}