设置超级源点s(此处标号为m的房间就是源点),如果房间k有入侵者(intruder),则存在一条有s指向k的弧,且容量为c(s,k)
=
INF;然后是处理由门联通的两个房间的关系了。
(
1
)如果房间i和j有门且cp在i,则c(i,j)
=
INF,c(j,i)
=
1
;
(
2
)如果房间i和j有门且cp在j,则c(i,j)
=
1
,c(j,i)
=
INF;
超级汇点t就是要保护的房间号码。计算从s到t的最大流ans.若ans
>=
INF,说明无法保护,否则ans为需要锁上的门的最小数量。
#include
<
iostream
>
#include
<
cstring
>
#include
<
string
>
#include
<
queue
>
#include
<
cstdio
>
using
namespace
std;
const
int
MAX
=
25
;
const
int
INF
=
2000
;
int
map[MAX][MAX],m,n,t,pre[MAX];
bool
vis[MAX];
int
Maxflow()
{
int
ans
=
0
;
while
(
true
)
{
memset(vis,
false
,
sizeof
(vis));
memset(pre,
0
,
sizeof
(pre));
queue
<
int
>
q; q.push(m); vis[m]
=
true
;
while
(
!
q.empty())
{
int
cur
=
q.front(); q.pop();
if
(cur
==
n)
break
;
for
(
int
i
=
0
;i
<
m;
++
i)
{
if
(
!
vis[i]
&&
map[cur][i])
{
vis[i]
=
true
; q.push(i); pre[i]
=
cur;
}
}
}
if
(
!
vis[n])
break
;
int
Min
=
INF,u;
for
( u
=
n;u
!=
m;u
=
pre[u])
{
if
(Min
>
map[pre[u]][u]) Min
=
map[pre[u]][u];
}
for
(u
=
n;u
!=
m;u
=
pre[u])
{
map[pre[u]][u]
-=
Min;
map[u][pre[u]]
+=
Min;
}
ans
+=
Min;
}
return
ans;
}
int
main()
{
int
i,lead_to,room;
string
is_intr;
scanf(
"
%d
"
,
&
t);
while
(t
--
)
{
memset(map,
0
,
sizeof
(map));
scanf(
"
%d %d
"
,
&
m,
&
n);
for
(i
=
0
;i
<
m;
++
i)
{
cin
>>
is_intr
>>
lead_to;
if
(is_intr
==
"
I
"
) map[m][i]
=
INF;
while
(lead_to
--
)
{
scanf(
"
%d
"
,
&
room); map[i][room]
=
INF; map[room][i]
++
;
}
}
int
ans
=
Maxflow();
if
(ans
>=
INF ) cout
<<
"
PANIC ROOM BREACH
"
<<
endl;
else
cout
<<
ans
<<
endl;
}
return
0
;
}