BOJ 热身赛 F题 解题报告 [最大流最小割 dinic]

题目在下面链接:

点击打开链接


F  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


题意:

给定m个房间,房间与房间之间有若干个锁,每个锁只能从固定的某个房间打开或者关闭。初始状态时每个锁都是关闭状态。

有一批侵入者分散在给定几个房间内。有一个房间是需要保护的。

问如果锁最少的门可以防止侵入者入侵。

思路:

感觉挺长的,英语不好伤不起。而且刚开始样例也没给全,不知道有重边情况。

显然是图论内容,每个房间是点,每个锁是边,如果锁i连接房间u和房间v,且可以从u打开或关闭这个锁。则是一条从u指向v的单向边。

首先处理一下点:

1.如果某个点v能间接或直接地抵达受保护点n,则v和n是等价点。即如果侵入者能到达v,即肯定能到达n。

2.如果某个房间有侵入者,则每个这个房间能间接或直接到达的房间,都和这个房间是等价点。

上两步的“间接或直接”抵达,用floyd处理即可。由1找出一个s集合,由2找出一个t集合。


这里需要一个预判,如果某个点即属于s集合,又属于t集合,则输出PANIC ROOM BREACH。

如果没有,则根据最大流最小割。

以s集合为源点,以t集合为汇点进行最大流即可得出答案。


至于为什么?

其本质在于最小割就是图之间使两个集合切断连接所需要的最小代价,刚好符合题意。


#include<iostream>
#include<vector>
#include<string>
#include<queue>
#include<algorithm>
#define llong long long
#define Min(a,b) (a<b?a:b)
#define Max(a,b) (a>b?a:b)
#define Abs(a) ((a)>0?(a):-(a))
#define Mod(a,b) (((a)-1+(b))%(b)+1)
using namespace std;
const int N=25;
const int inf=1000000000;
int n,m;
bool mat[N][N];
int mat2[N][N];
char str[5];
int d[N];
bool  vis[N];
int level[N];
void floyd()
{
	for(int k=0;k<m;k++)
		for(int i=0;i<m;i++)
			for(int j=0;j<m;j++)
				if(mat[i][k]&&mat[k][j])
					mat[i][j]=true;
}
bool bfs(int s,int t)
{
	memset(vis,0,sizeof(vis));
	memset(level,0,sizeof(level));
	queue<int> que;
	que.push(s);
	vis[s]=true;
	level[s]=0;
	while(!que.empty())
	{
		int now=que.front();
		que.pop();
		if(now==t)
		{
			return true;
		}
		for(int i=0;i<m+2;i++)
		{
			if(!vis[i]&&mat2[now][i])
			{
				vis[i]=true;
				level[i]=level[now]+1;
				que.push(i);
			}
		}
	}
	return false;
}
int dinic(int now,int sum,int t)
{
	if(now==t)
		return sum;
	int os=sum;
	for(int i=0;i<m+2 && sum;i++)
	{
		if(mat2[now][i]&&level[i]==level[now]+1)
		{
			int ret=dinic(i,Min(sum,mat2[now][i]),t);
			mat2[now][i]-=ret;
			mat2[i][now]+=ret;
			sum-=ret;
		}
	}
	return os-sum;
}
void solve(int s,int t)
{
	int ans=0;
	while(bfs(s,t))
		ans+=dinic(s,inf,t);
	printf("%d\n",ans);
}
int main()
{
	int cases;
	scanf("%d",&cases);
	while(cases--)
	{
		memset(mat,0,sizeof(mat));
		memset(mat2,0,sizeof(mat2));
		memset(d,0,sizeof(d));
		scanf("%d%d",&m,&n);
		for(int i=0;i<m;i++)
		{
			int tmp;
			scanf("%s",str);
			if(str[0]=='I')
			{
				d[i]=1;
			}
			scanf("%d",&tmp);
			for(int j=1;j<=tmp;j++)
			{
				int v;
				scanf("%d",&v);
				mat[i][v]=true;
				mat2[i][v]++;
			}
		}
		floyd();
		bool flag=true;
		for(int i=0;i<m;i++)
		{
			if(d[i])
			{
				for(int j=0;j<m;j++)
				{
					if(mat[i][j])
					{
						d[j]=1;
						if(j==n)
							flag=false;
					}
				}
			}
		}
		if(!flag)
		{
			printf("PANIC ROOM BREACH\n");
			continue;
		}
		for(int i=0;i<m;i++)
			if(mat[i][n]||i==n)
			{
				d[i]=2;
			}

		int s=m;
		int t=m+1;
		for(int i=0;i<m;i++)
			if(d[i]==2)
			{
				mat2[s][i]=inf;
			}
			else if(d[i]==1)
			{
				mat2[i][t]=inf;
			}
		solve(s,t);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值