poj3084 Panic Room 最小割

感觉做图论需要强大的yy能力啊。。。
这道题难就难在建图,之后就是一个最小割的过程。
1:题目中要我们保护的房间就是汇点t,然后我们要额外增加一个源点s;
2:存在intruder的房间,我们将它与源点连一条弧(s,j,INF)。
3:其他房间如果i->j  则我们要连两条弧 (i,j,INF) (j,i,1); (这里需要yy一下,因为源点直接与存在intruder的房间相连,并且网络是有向图,这个时候问题就被我们转变为,去掉最少权值和的边能使源点与汇点不连通的问题,这就是一个最小割的问题。然后再来就是为什么要连两条弧的问题。因为弧是有向的,如果intruder要从i到j,因为锁在房间i中,所以无论如何都关不住,所以赋值为INF。但是如果intruder要从j进入到i,因为锁在i,所以我们只要关一把锁,就可以了,所以弧赋值为1.(可以参照下面的图YY一下。。。。与源点相连的是存在intruder的房间,如果i到j的弧是无限大那么锁在i中,t是我们要保护的房间。相当于是吧intruder反锁在门外,i到j的弧是1的话说明关一扇门可以阻断这条路。)
 
最后求完最大流之后,如果最大流大于等于INF,则不存在方案,否则输出最大流的值。
Panic Room
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 1585 Accepted: 785

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
#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

#define INF 0xFFFFFF
#define MAXN 30

struct edge
{
	int to,c,next;
};

edge e[999999];
char type[10];
int head[MAXN],head2[MAXN],en;
int n,m,st,ed,dis[MAXN],pre[MAXN],que[MAXN],maxflow;

void add(int a,int b,int c)
{
	e[en].to=b;
	e[en].c=c;
	e[en].next=head[a];
	head[a]=en++;
	e[en].to=a;
	e[en].c=0;
	e[en].next=head[b];
	head[b]=en++;	
} 


bool bfs() 
{
	memset(dis,-1,sizeof(dis));
	que[0]=st,dis[st]=1;
	int t=1,f=0;
	while(f<t)
	{
		int j=que[f++];
		for(int k=head[j];k!=-1;k=e[k].next)
		{	
			int i=e[k].to;
			if(dis[i]==-1 && e[k].c)
			{
				que[t++]=i;
				dis[i]=dis[j]+1;
				if(i==ed) return true;
			}
		}
	}
	return false; 
} 


int update()  
{  
	int p,flow=INF;  
    for (int i=pre[ed];i!=-1;i=pre[i])
		if(e[head2[i]].c<flow) p=i,flow=e[head2[i]].c;    
    for (int i=pre[ed];i!=-1;i=pre[i]) 
		e[head2[i]].c-=flow,e[head2[i]^1].c+=flow;   
    maxflow+=flow; 
    return p;
}  

void dfs()  
{  
	memset(pre,-1,sizeof(pre));
	memcpy(head2,head,sizeof(head2));  
    for(int i=st,j;i!=-1;)  
    {  
        int flag=false;  
        for(int k=head[i];k!=-1;k=e[k].next)    
          if(e[k].c && (dis[j=e[k].to]==dis[i]+1) )  
          {  
                pre[j]=i; 
				head2[i]=k;  
				i=j; 
				flag=true;  
                if(i==ed) 
					i=update();  
                if(flag) 
					break;  
          }  
        if (!flag) dis[i]=-1,i=pre[i];   
    }  
} 



void solve()
{
	int nn;
	scanf("%d%d",&n,&ed);
	st=n,en=0;
	memset(head,-1,sizeof(head));
	for(int i=0;i<n;i++)
	{
		scanf("%s",type);
		if(type[0]=='I')
			add(st,i,INF);
		scanf("%d",&nn);
		for(int k=0;k<nn;k++)
		{
			int j;
			scanf("%d",&j);
			add(i,j,INF),add(j,i,1);
		}
	}
	maxflow=0;
	while(bfs())
		dfs();
	if(maxflow<INF)
		printf("%d\n",maxflow);
	else
		printf("PANIC ROOM BREACH\n");
	
}

int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
		solve();
	return 0;
}
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值