题意:有一些建在一起的房间,相互之间通过门相连,一个门的控制开关在它连接的两个房间的其中一个里面,在有开关的房间可以任意进入没开关的另一侧房间,而在另一侧要进入有开关的房间则需要门是开着的。现在有的房间中有入侵者,同时有一个房间n需要保护,问要保护那个房间不被入侵,最少要关上几道门。如果没法实现,则输出“PANIC ROOM BREACH”。比如“I3 0 4 5”,则表示有入侵者,这间房有0,4,5房间的key。
解题:关键部分就是建图。n就是汇点。
题目中要我们保护的房间就是汇点t,然后我们要额外增加一个源点s;
存在intruder的房间,我们将它与源点连一条弧(s,j,INF)。
其他房间如果i->j 则我们要连两条弧 (i,j,INF) (j,i,1); (PS:因为源点直接与存在intruder(入侵者)的房间相连,并且网络是有向图,这个时候问题就被我们转变为,去掉最少权值和的边能使源点与汇点不连通的问题,这就是一个最小割的问题。然后再来就是为什么要连两条弧的问题。因为弧是有向的,如果intruder要从i到j,因为锁在房间i中,所以无论如何都关不住,所以赋值为INF。但是如果intruder要从j进入到i,因为锁在i,所以我们只要关一把锁,就可以了,所以弧赋值为1.)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cctype>
using namespace std;
#define MIN(a,b) (a)<(b)? a:b
#define INF 2000000
int cap[25][25],flow[25][25];
int vit[25],lev[25];
int n,m;
bool bfs(int st,int ed,int beg,int End)
{
memset(lev,0x1f,sizeof(lev));
int que[25];
int Front,rear;
Front=rear=0;
que[Front++]=beg;
memset(vit,0,sizeof(vit));
vit[beg]=1;
lev[beg]=0;
while(rear<Front)
{
int t=que[rear];
rear++;
for(int i=st;i<=ed;i++)
{
if(cap[t][i]>flow[t][i]&&!vit[i])
{
que[Front++]=i;
vit[i]=1;
lev[i]=lev[t]+1;
}
}
}
if(lev[End]<INF)
return true;
return false;
}
int dfs(int v,int st,int ed,int beg,int fl)
{
int ret=0;
if(v == n||fl==0)
return fl;
for(int i=st;i<=ed;i++)
{
if(fl==0)
break;
if(cap[v][i]>flow[v][i]&&lev[v]+1==lev[i])
{
int f=MIN(cap[v][i]-flow[v][i],fl);
int r = dfs(i,st,ed,beg,f);
ret+=r;
fl-=r;
flow[v][i]+=r;
flow[i][v]-=r;
}
}
if(ret==0)
lev[v] = INF;
return ret;
}
int dinic(int st,int ed,int beg,int End)
{
int ret=0;
while(bfs(st,ed,beg,End))
{
int r=dfs(beg,st,ed,beg,INF);
if(r == 0)
break;
ret+=r;
}
return ret;
}
int main()
{
int T,c;
cin>>T;
while(T--)
{
memset(cap,0,sizeof(cap));
memset(flow,0,sizeof(flow));
cin>>m>>n;
for(int i=0;i<m;i++)
{
char ch[5];
scanf("%s",ch);
scanf("%d",&c);
if(strcmp(ch,"I")==0)
cap[m][i]=INF;
for(int j=0;j<c;j++)
{
int x;
cin>>x;
cap[i][x]=INF;
if(cap[x][i]<INF)
cap[x][i]++;
}
}
int ret=dinic(0,m,m,n);
if(ret<INF)
cout<<ret<<endl;
else
cout<<"PANIC ROOM BREACH"<<endl;
}
}