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 }