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:
  1. 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).
  2. 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;
}