[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 }

 

posted @ 2017-06-20 16:27  Kirai  阅读(150)  评论(0编辑  收藏  举报