spoj 1693 Coconuts 最小割 二者取其一式

题目链接: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\n", flow);
104     }
105     return 0;
106 }

 

转载于:https://www.cnblogs.com/titicia/p/5276841.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值