sicily 1402Panic Room(最大流最小割)

View Code
   
     
设置超级源点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 ;
}

你可能感兴趣的:(oom)