题目链接:http://www.spoj.com/problems/COCONUTS/
题意:N个城堡守卫就非洲的燕子能否搬运椰子而进行投票,每个人有自己的看法,但是为了避免跟自己的朋友持相反意见,他们时常会投相反的票。
现在给出每个人的初始看法以及朋友关系,求在某种投票方案下,违背自己意愿与持不同意见的朋友对数的总和最小。
思路:参考Edelweiss的《网络流建模汇总》。这是一个二者取其一式问题。
设置超级源点S和T。
每名守卫i如果赞成,连边s->i,容量为1;连边i->t,容量为0。
如果反对,连边i->t,容量为1;连边s-i,容量为0。
如果i和j是朋友,连边i->j和j->i,容量均为1。
然后求最小割就可以了。
1 #include <bits/stdc++.h> 2 using namespace std; 3 int n, m, s, t; 4 #define maxn 310 5 #define inf 0x3f3f3f3f 6 struct Edge 7 { 8 int from, to, cap, flow; 9 Edge(int f, int t, int c, int fl) 10 { 11 from = f; to = t; cap = c; flow = fl; 12 } 13 }; 14 vector <Edge> edges; 15 vector <int> G[maxn]; 16 int cur[maxn], vis[maxn], d[maxn]; 17 void AddEdge(int from, int to, int cap) 18 { 19 edges.push_back(Edge(from, to, cap, 0)); 20 edges.push_back(Edge(to, from, 0, 0)); 21 m = edges.size(); 22 G[from].push_back(m-2); 23 G[to].push_back(m-1); 24 } 25 bool bfs() 26 { 27 memset(vis, 0, sizeof(vis)); 28 d[s] = 0; vis[s] = 1; 29 queue <int> q; 30 q.push(s); 31 while(!q.empty()) 32 { 33 int x = q.front(); q.pop(); 34 for(int i = 0; i < G[x].size(); i++) 35 { 36 Edge &e = edges[G[x][i]]; 37 if(!vis[e.to] && e.cap > e.flow) 38 { 39 d[e.to] = d[x]+1; 40 vis[e.to] = 1; 41 q.push(e.to); 42 } 43 } 44 } 45 return vis[t]; 46 } 47 int dfs(int x, int a) 48 { 49 if(x == t || a == 0) return a; 50 int flow = 0, f; 51 for(int &i = cur[x]; i < G[x].size(); i++) 52 { 53 Edge &e = edges[G[x][i]]; 54 if(d[x]+1 == d[e.to] && (f = dfs(e.to, min(e.cap - e.flow, a))) > 0) 55 { 56 e.flow += f; 57 edges[G[x][i]^1].flow -= f; 58 flow += f; 59 a -= f; 60 if(a == 0) break; 61 } 62 } 63 return flow; 64 } 65 int maxflow() 66 { 67 int flow = 0; 68 while(bfs()) 69 { 70 memset(cur, 0, sizeof(cur)); 71 flow += dfs(s, inf); 72 } 73 return flow; 74 } 75 int N, M; 76 int main() 77 { 78 // freopen("in.txt", "r", stdin); 79 // freopen("out.txt", "w", stdout); 80 while(scanf("%d%d", &N, &M) && (N+M)) 81 { 82 edges.clear(); 83 s = 0; t = N+1; 84 for(int i = 0; i <= t; i++) G[i].clear(); 85 for(int i = 1; i <= N; i++) 86 { 87 int a; scanf("%d", &a); 88 if(a) 89 { 90 AddEdge(s, i, 1); AddEdge(i, t, 0); 91 } 92 else 93 { 94 AddEdge(s, i, 0); AddEdge(i, t, 1); 95 } 96 } 97 for(int i = 1; i <= M; i++) 98 { 99 int a, b; scanf("%d%d", &a, &b); 100 AddEdge(a, b, 1); AddEdge(b, a, 1); 101 } 102 int flow = maxflow(); 103 printf("%d ", flow); 104 } 105 return 0; 106 }