[51nod1299] 监狱逃离(最小点覆盖)
题目链接:https://www.51nod.com/contest/problem.html#!problemId=1299
题意:中文题面。
挺容易想到最小点覆盖的,这么想题目的意思就是希望找到几个点,保证让某些点不能与叶子连通。问最少覆盖几个点可以达到这个目的,要求的某些点不能作为覆盖的点。
把每个点拆成入点和出点u和u+n,按照下述方式建图:
1.每一个点能覆盖则u->u+n,容量为1。表示这个点可以放警卫。
2.叶子的出点到汇点容量为1。表示警察可以在出口。
3.假如没有犯人,说明这个点可以覆盖,入点和出点建边,容量为1。
4.源点到要求点的出点建边,容量为inf。表示有犯人不能被覆盖。
5.图的状态用出点到入点,容量为inf。表示连通的状态。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef struct Edge { int u, v, w, next; }Edge; 5 const int inf = 0x7f7f7f7f; 6 const int maxn = 200100; 7 int cnt, dhead[maxn]; 8 int cur[maxn], dd[maxn]; 9 Edge dedge[maxn<<4]; 10 int S, T, N; 11 int n, m, dig[maxn]; 12 bool vis[maxn]; 13 14 void init() { 15 memset(dhead, -1, sizeof(dhead)); 16 for(int i = 0; i < maxn; i++) dedge[i].next = -1; 17 S = 0; cnt = 0; 18 } 19 20 void adde(int u, int v, int w, int c1=0) { 21 dedge[cnt].u = u; dedge[cnt].v = v; dedge[cnt].w = w; 22 dedge[cnt].next = dhead[u]; dhead[u] = cnt++; 23 dedge[cnt].u = v; dedge[cnt].v = u; dedge[cnt].w = c1; 24 dedge[cnt].next = dhead[v]; dhead[v] = cnt++; 25 } 26 27 bool bfs(int s, int t, int n) { 28 // memset(vis, 0, sizeof(vis)); 29 queue<int> q; 30 for(int i = 0; i < n; i++) dd[i] = inf; 31 dd[s] = 0; 32 q.push(s); 33 while(!q.empty()) { 34 int u = q.front(); q.pop(); 35 for(int i = dhead[u]; ~i; i = dedge[i].next) { 36 if(dd[dedge[i].v] > dd[u] + 1 && dedge[i].w > 0) { 37 dd[dedge[i].v] = dd[u] + 1; 38 // vis[dedge[i].v] = 1; 39 if(dedge[i].v == t) return 1; 40 q.push(dedge[i].v); 41 } 42 } 43 } 44 return 0; 45 } 46 47 int dinic(int s, int t, int n) { 48 int st[maxn], top; 49 int u; 50 int flow = 0; 51 while(bfs(s, t, n)) { 52 for(int i = 0; i < n; i++) cur[i] = dhead[i]; 53 u = s; top = 0; 54 while(cur[s] != -1) { 55 if(u == t) { 56 int tp = inf; 57 for(int i = top - 1; i >= 0; i--) { 58 tp = min(tp, dedge[st[i]].w); 59 } 60 flow += tp; 61 for(int i = top - 1; i >= 0; i--) { 62 dedge[st[i]].w -= tp; 63 dedge[st[i] ^ 1].w += tp; 64 if(dedge[st[i]].w == 0) top = i; 65 } 66 u = dedge[st[top]].u; 67 } 68 else if(cur[u] != -1 && dedge[cur[u]].w > 0 && dd[u] + 1 == dd[dedge[cur[u]].v]) { 69 st[top++] = cur[u]; 70 u = dedge[cur[u]].v; 71 } 72 else { 73 while(u != s && cur[u] == -1) { 74 u = dedge[st[--top]].u; 75 } 76 cur[u] = dedge[cur[u]].next; 77 } 78 } 79 } 80 return flow; 81 } 82 83 inline bool scan_d(int &num) { 84 char in;bool IsN=false; 85 in=getchar(); 86 if(in==EOF) return false; 87 while(in!='-'&&(in<'0'||in>'9')) in=getchar(); 88 if(in=='-'){ IsN=true;num=0;} 89 else num=in-'0'; 90 while(in=getchar(),in>='0'&&in<='9'){ 91 num*=10,num+=in-'0'; 92 } 93 if(IsN) num=-num; 94 return true; 95 } 96 97 signed main() { 98 // freopen("in", "r", stdin); 99 int u, v; 100 while(scan_d(n)) { 101 scan_d(m); 102 init(); 103 S = 0, T = 2 * ++n + 1, N = T + 1; 104 memset(vis, 0, sizeof(vis)); 105 memset(dig, 0, sizeof(dig)); 106 for(int i = 1; i < n; i++) { 107 scan_d(u); scan_d(v); 108 adde(++u+n, ++v, inf); 109 adde(v+n, u, inf); 110 dig[u]++, dig[v]++; 111 } 112 for(int i = 1; i <= m; i++) { 113 scan_d(u); 114 adde(S, ++u+n, inf); 115 vis[u] = 1; 116 } 117 for(int i = 1; i <= n; i++) if(!vis[i]) adde(i, i+n, 1); 118 for(int i = 1; i <= n; i++) if(dig[i] == 1) adde(i+n, T, 1); 119 int ret = dinic(S, T, N); 120 if(ret >= inf) printf("-1\n"); 121 else printf("%d\n", ret); 122 } 123 return 0; 124 }