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:
![](http://acm.bupt.edu.cn/onlinejudge/newoj/problem_upload_picture/2011_03_15_16_17_24.png)
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.
Sampleinput
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
Sampleoutput
2
PANIC ROOM BREACH
1
解题思路:这个题是多个源点,一个汇点最大流的问题。题目的意思是如果入侵者所在的房间里面是控制室,那么他到别的房间所需要的锁数是无穷大,因为没有锁可以锁住他,如果他所在的房间不是控制室,那么有几条路径到另一个房间,那么那条路径的容量就是几。连接一个超级源点到入侵者所在的房间,容量为无穷。然后利用最大流算法(直到没有增广路径为止),找出最小割(最大流)就是需要开的锁的数量。如果大于等于无穷,则该题无解,即入侵者一定能进入到要保护的房间。
package OJ;
import java.util.*;
import java.math.*;
public class P15_temp {
final int INF = 1<<16;
final int MAX = 25;
int[][] map = new int[MAX][MAX]; //邻接矩阵,
int[] path = new int[MAX];//记录路径:记录每个点所在路径的前一个点
int n = 0;
public int bfs(int start, int end){ //进行广度优先搜索,找到最小的流
int[] flow = new int[MAX];
for(int i=0; i<MAX; i++)//初始化路径
path[i] = -1;
path[start]=0;//设源点的路径为0
flow[start]=INF;//设源点的流为最大值
ArrayDeque<Integer> q = new ArrayDeque<Integer>();
q.push(start);
while (!q.isEmpty())
{
int cur=q.poll();
if(cur==end)//假如当前结点等于汇点,结束搜索
break;
for(int i=0;i<=n;i++)//最后一个n是超级源点
//map中存的是容量
if(path[i]==-1 && map[cur][i]!=0) //找到每个点的前驱和每条边的流
{
flow[i]=Math.min(map[cur][i],flow[cur]);
q.push(i);
path[i]=cur;
}
}
if(path[end]==-1)
return -1;
return flow[end];
}
public int Edmondes_Karp(int start, int end){
int max_flow=0,flow; //最大流, 流
while((flow=bfs(start,end))!=-1)//假如超级源点有到汇点的增广路径
{
max_flow+=flow;
int cur=end;
while(cur!=start) //反向走一遍路径,修改每条边的流
{
int pre=path[cur];
map[pre][cur]-=flow;
map[cur][pre]+=flow;
cur=pre;
}
}
return max_flow;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int t;
Scanner in = new Scanner(System.in);
t = in.nextInt();//总共数据集的个数
int results = t;
int[] anss = new int[t];
int max = 1<<16;
while(t>0){
int end,c,d;
P15_temp pt = new P15_temp();
pt.n = in.nextInt(); //房间数
end = in.nextInt(); //需要保护的房间,即汇点
for(int i=0; i<pt.n; i++){
char[] str = new char[5];
str = in.next().toCharArray();//是不是有坏人
if(str[0] == 'I')
pt.map[pt.n][i] = pt.INF;//超级源点到汇点设置为最大值
c = in.nextInt(); //该房间连通的房间数
while(c>0){
d = in.nextInt();
pt.map[i][d] = pt.INF;
pt.map[d][i]++;
c--;
}
}
int ans = pt.Edmondes_Karp(pt.n, end);//每次都是超级源点为起点, 汇点
// if(ans>=pt.INF)
// System.out.println("PANIC ROOM BREACH");
// else
// System.out.println(ans);
anss[results-t] = ans;
t--;
}
for(int j=0; j<results; j++){
if(anss[j]>=max)
System.out.println("PANIC ROOM BREACH");
else
System.out.println(anss[j]);
}
}
}