USACO 5.4 Character Recognition (最小点割集)

2015-04-03 23:36:48

思路:这题求的是最小点割集,但我们可以将其转化为求最小边割集的问题。将每个点拆点,建边,容量为1。然后根据输入也可以建边。

  这样我们不妨以c1的输入点和c2的输出点为起点和终点,跑一遍最大流,求出最小点割集的数量。

  因为要求字典序,可以枚举删除1~N每个点,如果删除完后求一遍最大流流量减少了1,那么取这个点为答案,并且永久删除(为了保证后面取点的正确性)

  直到取的点数足够就输出。

  1 /*
  2 ID:naturec1
  3 PROG: telecow
  4 LANG: C++
  5 */
  6 #include <cstdio>
  7 #include <cstring>
  8 #include <cstdlib>
  9 #include <cmath>
 10 #include <vector>
 11 #include <map>
 12 #include <set>
 13 #include <stack>
 14 #include <queue>
 15 #include <string>
 16 #include <iostream>
 17 #include <algorithm>
 18 using namespace std;
 19 
 20 #define MEM(a,b) memset(a,b,sizeof(a))
 21 #define REP(i,n) for(int i=0;i<(n);++i)
 22 #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
 23 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
 24 #define MP(a,b) make_pair(a,b)
 25 
 26 typedef long long ll;
 27 typedef pair<int,int> pii;
 28 const int INF = (1 << 30) - 1;
 29 const int MAXN = 210;
 30 const int MAXM = 1210;
 31 
 32 int N,M,c1,c2,st,ed;
 33 int first[MAXN],ecnt;
 34 int lev[MAXN],avoid[MAXN];
 35 
 36 struct edge{
 37     int v,next,cp;
 38 }e[MAXM * 4],e_st[MAXM * 4];
 39 
 40 void Init(){
 41     MEM(first,-1);
 42     ecnt = 0;
 43 }
 44 
 45 void Add_edge(int u,int v,int c){
 46     e[ecnt].next = first[u];
 47     e[ecnt].v = v;
 48     e[ecnt].cp = c;
 49     first[u] = ecnt++;
 50 
 51     e[ecnt].next = first[v];
 52     e[ecnt].v = u;
 53     e[ecnt].cp = 0;
 54     first[v] = ecnt++;
 55 }
 56 
 57 bool Bfs(){
 58     queue<int> Q;
 59     while(!Q.empty()) Q.pop();
 60     Q.push(st);
 61     MEM(lev,-1);
 62     lev[st] = 0;
 63     while(!Q.empty()){
 64         int x = Q.front(); Q.pop();
 65         for(int i = first[x]; ~i; i = e[i].next){
 66             int v = e[i].v;
 67             if(!avoid[v] && e[i].cp > 0 && lev[v] < 0){
 68                 lev[v] = lev[x] + 1;
 69                 Q.push(v);
 70             }
 71         }
 72     }
 73     return lev[ed] != -1;
 74 }
 75 
 76 int Dfs(int p,int minf){
 77     if(p == ed) return minf;
 78     for(int i = first[p]; ~i; i = e[i].next){
 79         int v = e[i].v;
 80         if(!avoid[v] && e[i].cp > 0 && lev[v] == lev[p] + 1){
 81             int d = Dfs(v,min(e[i].cp,minf));
 82             if(d > 0){
 83                 e[i].cp -= d;
 84                 e[i ^ 1].cp += d;
 85                 return d;
 86             }
 87         }
 88     }
 89     return 0;
 90 }
 91 
 92 int Dinic(){
 93     int max_flow = 0,cur;
 94     while(Bfs()){
 95         while((cur = Dfs(c1,INF)) > 0)
 96             max_flow += cur;
 97     }
 98     return max_flow;
 99 }
100 
101 int main(){
102     freopen("telecow.in","r",stdin);
103     freopen("telecow.out","w",stdout);
104     Init();
105     int a,b;
106     scanf("%d%d%d%d",&N,&M,&c1,&c2);
107     st = c1;
108     ed = c2 + N;
109     //拆点
110     FOR(i,1,N){
111         if(i == c1 || i == c2){
112             Add_edge(i,i + N,INF);
113         }
114         else{
115             Add_edge(i,i + N,1);
116         }
117     }
118     REP(i,M){
119         scanf("%d%d",&a,&b);
120         Add_edge(a + N,b,1);
121         Add_edge(b + N,a,1);
122     }
123     memcpy(e_st,e,sizeof(e));
124     int max_flow = Dinic();
125     printf("%d\n",max_flow);
126     vector<int> ans;
127     FOR(i,1,N) if(i != c1 && i != c2){
128         memcpy(e,e_st,sizeof(e_st));
129         avoid[i] = avoid[i + N] = 1;
130         int cur = Dinic();
131         if(cur == max_flow - 1 - ans.size()) ans.push_back(i);
132         else avoid[i] = avoid[i + N] = 0;
133         if(ans.size() >= max_flow) break;
134     }
135     if(max_flow){
136         printf("%d",ans[0]);
137         for(int i = 1; i < ans.size(); ++i) printf(" %d",ans[i]);
138         puts("");
139     }
140     return 0;
141 }

 

posted @ 2015-04-03 23:53  Naturain  阅读(150)  评论(0编辑  收藏  举报