本题能够说是最小割入门级题目。
假设能想到是最小割问题。那么建图思路便是水到渠成的事了。
加入一个源点S和汇点T;
把S与每一个间谍相连。容量为无穷大;
把城市N(即飞机场的位置)与汇点T相连。容量为无穷大;
之间有道路的城市相连。容量为1,注意这里是双向的边;
建图完后,依据最大流最小割定理。那么直接求最大流就可以。
闲话少说,上代码:
#include<iostream> using namespace std; #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<string> #include<queue> #include<stack> #include<map> #include<vector> #include<algorithm> #define INS 1<<30 #define CLR(arr,v) memset(arr,v,sizeof(arr)) #define MaxV 3000 #define MaxE 100000 class MaxFlow{ public: void Clear(){ CLR(h,-1); CLR(cnt,0); CLR(vis,0); flag = false; pos = top = head = total = maxflow = 0; } void add(int u,int v,int flow){ num[pos] = v; sur[pos] = flow; next[pos] = h[u]; h[u] = pos++; num[pos] = u; sur[pos] = 0; next[pos] = h[v]; h[v] = pos++; } int GetMaxFlow(int s,int t){ init(t); stk[top] = s; while(!flag){ minres = INS; if(top < 0) top = 0; if(!dfs(stk[top],-1,t,minres)) continue; maxflow += minres; while(dis != -1){ sur[dis] -= minres; sur[dis^1] += minres; dis = pre_e[dis]; } top = 0; } return maxflow; } private: int h[MaxV],num[MaxE],sur[MaxE],next[MaxE],gap[MaxV],cnt[MaxV],pre_e[MaxE],stk[MaxV],que[MaxV]; int pos,top,head,total,maxflow,minres,dis; bool vis[MaxV],flag; void init(int n){ que[total++] = n; vis[n] = true; while(head < total){ int p = que[head++]; if(head >= MaxV) head -= MaxV; for(int i = h[p]; i != -1 ;i = next[i]){ if(!vis[ num[i] ]){ vis[ num[i] ] = true; gap[ num[i] ] = gap[p] + 1; cnt[ gap[ num[i] ] ]++; que[total++] = num[i]; if(total >= MaxV) total -= MaxV; } } } } bool dfs(int p,int father,int n,int &minres){ int m = minres; for(int i = h[p]; i != -1 ;i = next[i]){ if(sur[i] > 0 && gap[p] - gap[ num[i] ] == 1){ minres = min(minres,sur[i]); pre_e[i] = father; if(num[i] != n) stk[++top] = num[i]; if(num[i] == n || dfs(num[i],i,n,minres)) { if(num[i] == n) dis = i; return true; } minres = m; } } cnt[ gap[p] ]--; cnt[ gap[p] + 1]++; top--; if(cnt[ gap[p] ] == 0) flag = true; gap[p] += 1; return false; } }T; int main() { int t; scanf("%d",&t); int cnt = 0; while (t--) { int n,m,p; scanf("%d%d%d",&n,&m,&p); int N = n + 1; T.Clear(); int x; for (int i = 1; i <= p; ++ i) scanf("%d",&x),T.add(0,x,INS); for (int i = 1; i <= m; ++ i) { int u,v; scanf("%d%d",&u,&v); T.add(u,v,1); T.add(v,u,1); } T.add(n,N,INS); printf("Case #%d: %d\n",++cnt,T.GetMaxFlow(0,N)); } return 0; }