题意:有m个房间,你需要保护第n个房间使得其不被攻入。房间与房间之间会有门,门上有机关,因此当门关上时,只能从一边进入另外一边而不能从相反方向进入。现在告诉你这n个房间以及门的分布情况,以及开始的时候哪些房间里有贼,问至少关掉几个门使得房间n不被攻入。
感觉这个题目蛮有意思的。比较容易想到最小割。如果从房间a到房间b有一个门,如果这个门关上了,且门上的机关使得贼只能从a进入b而不能让其从b进入a,那么这里对应两条边(a,b,inf),(b,a,1),如果房间i里面有贼,对应边(S,i,inf),而需要保护的那个房间n就会汇点T。然后求一遍最大流。如果maxflow>=inf就说明不存在合法方案了,否则maxflow就是答案。而流的意思就是要关掉多少扇门了。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define maxn 25 5 #define maxm 1000000 6 #define INF 1<<20 7 using namespace std; 8 int v[maxm],next[maxm],w[maxm]; 9 int first[maxn],q[maxn],d[maxn],work[maxn]; 10 int e,S,T; 11 12 void init(){ 13 e = 0; 14 memset(first,-1,sizeof(first)); 15 } 16 17 void add_edge(int a,int b,int c){ 18 v[e] = b;next[e] = first[a];w[e] = c;first[a] = e++; 19 } 20 21 int bfs(){ 22 int rear = 0; 23 memset(d,-1,sizeof(d)); 24 d[S] = 0;q[rear++] = S; 25 for(int i = 0;i < rear;i++){ 26 for(int j = first[q[i]];j != -1;j = next[j]) 27 if(w[j] && d[v[j]] == -1){ 28 d[v[j]] = d[q[i]] + 1; 29 q[rear++] = v[j]; 30 if(v[j] == T) return 1; 31 } 32 } 33 return 0; 34 } 35 36 int dfs(int cur,int a){ 37 if(cur == T) return a; 38 for(int &i = work[cur];i != -1;i = next[i]){ 39 if(w[i] && d[v[i]] == d[cur] + 1) 40 if(int t = dfs(v[i],min(a,w[i]))){ 41 w[i] -= t;w[i^1] += t; 42 return t; 43 } 44 } 45 return 0; 46 } 47 48 int dinic(){ 49 int ans = 0; 50 while(bfs()){ 51 memcpy(work,first,sizeof(first)); 52 ans += dfs(S,INF); 53 } 54 return ans; 55 } 56 57 int main() 58 { 59 int kase,n; 60 char str[10]; 61 scanf("%d",&kase); 62 while(kase--){ 63 init(); 64 scanf("%d%d",&n,&T); 65 S = n+1; 66 for(int i = 0;i < n;i++){ 67 int c,num; 68 scanf("%s %d",str,&c); 69 if(str[0] == 'I'){ 70 add_edge(S,i,INF); 71 add_edge(i,S,0); 72 } 73 while(c--){ 74 scanf("%d",&num); 75 add_edge(i,num,INF); 76 add_edge(num,i,1); 77 } 78 } 79 int ans = dinic(); 80 if(ans >= INF) printf("PANIC ROOM BREACH "); 81 else printf("%d ",ans); 82 } 83 return 0; 84 }