第十二周:[Sicily]1402. 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 – 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 – 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
Copy sample input to clipboard
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

最小割。读懂题意花了点时间,其实就是有向图里,将有攻击者的房间和需要保护的房间切断联系,分割成几个子图,子图之间不能互相到达,求最小分割的边数。这样的话,其实就是求最小割,也就是求最大流。输入数据稍作处理,因为有攻击者的房间可能不止一个,所以不能直接将攻击者的房间作为唯一的源点,而是自己设置一个源点,指向这些有攻击者的房间,边容量为INF值,汇点即需要保护的房间。输入数据中,每组数据给的是该房间能通向的房间,按照这个方向的话,汇点是各个有攻击者的房间,和要求的相反,所以处理输入的时候,将输入数据的方向反过来,剩余网络中的反向边则设为INF值,例如,输入数据为0、1,处理时map[1][0] ++(两个房间之间有可能有多扇门,不能直接赋为1),map[0][1] = INF,然后求map的最大流。

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;

int m,n,map[21][21];

int find_max_flow(){
    bool findpath = true;
    int ans = 0;
    while(findpath){
        bool visit[21] = {false};
        int pre[21] = {-1},cur_flow,pre_flow,cur_point;
        queue<int> q;
        q.push(m);
        visit[m] = true;
        findpath = false;
        while(!q.empty()){
            int now = q.front(),i;
            q.pop();
            if(map[now][n] > 0){
                findpath = true;
                cur_point = now;
                cur_flow = map[cur_point][n];
                while(pre[cur_point] != m){
                    pre_flow = map[pre[cur_point]][cur_point];
                    cur_flow = cur_flow > pre_flow ? pre_flow : cur_flow;
                    cur_point = pre[cur_point];
                }
                ans += cur_flow;
                map[now][n] -= cur_flow;
                map[n][now] += cur_flow;
                while(pre[now] != m){
                    map[pre[now]][now] -= cur_flow;
                    map[now][pre[now]] += cur_flow;
                    now = pre[now];
                }
                break;
            }
            for(i = 0;i < m;i++)
                if(map[now][i] > 0 && visit[i] == false){
                    q.push(i);
                    pre[i] = now;
                    visit[i] = true;
            }
        }
    }
    return ans;
}

int main(){
    int x;
    int INF = 400;
    cin>>x;
    while(x--){
        int i,num_edge,r,ans;
        bool found_ans = false;
        string s;
        memset(map,0, sizeof(map));
        cin>>m>>n;
        for(i = 0;i < m;i++){
            cin>>s>>num_edge;
            if(s == "I")
                map[m][i] = INF;
            while(num_edge--){
                cin>>r;
                if(s == "I" && r == n){
                    cout<<"PANIC ROOM BREACH"<<endl;
                    found_ans = true;
                }
                map[r][i] ++;
                map[i][r] = INF;
            }
        }
        if(!found_ans)
            cout<<find_max_flow()<<endl;
    }
    return 0;
}
点赞