【最小割--二种决策选一】【SPOJ1693】Coconut

【题目来源】http://www.spoj.com/problems/COCONUTS/

 

【问题描述】N个城堡守卫正在就非洲的燕子能否搬运椰子而进行投票。每个人都有自己的看法,但是为了避免跟自己的朋友持相反意见,他们时常会投相反的票。现在给出每个人的初始看法以及朋友关系,求在某种投票方案下,违背自己意愿的票数与持不同意见的朋友对数的总和最小。(2 <= N <= 300, 1 <= M <= N(N-1)/2

 

【问题分析】本题属于二种决策选一的经典最小割模型。设立源点S和汇点T,把每个城堡守卫看成点,连接S到每个守卫再到汇点T。如果这个守卫自己的看法为赞同,那么就边守卫->T的容量为1,边S->守卫的容量为0;反之亦然。对于每对朋友关系,连接i->j和j->i,容量为1。

       建模分析 : 割对应实际问题的时候,相当于选择边加入割集,并且要使得不存在一条从S->T的路径。倘若选择了S->守卫,表示选择了赞同,边上的容量即为选择赞同的代价,如果这个人原先是想投赞同票,那么边上容量为0,也就相当于没有代价;反之,如果这个人原先是想投反对票,那么边上的容量为1,相当于记录下了他违背自己意愿。并且,对于一对朋友之间,如果2个人的选择不同,那么仍然会存在一条从S->T的路径。此时需要再选取一条边,就是这对朋友i和j之间边的容量,也就是这对朋友选择不同的代价。

 

【代码如下】

 

 

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <climits>
  4 #include <cstring>
  5 #include <vector>
  6 #include <deque>
  7 #include <algorithm>
  8 
  9 #define FILE_IO
 10 
 11 using namespace std;
 12 
 13 const int Maxn = 302, INF = INT_MAX;
 14 
 15 struct edge
 16 {
 17     int v, c;
 18     edge* next, * op;
 19     edge(int _v, int _c, edge* _next) : v(_v), c(_c), next(_next) {}
 20 }* E[Maxn], * Et[Maxn];
 21 
 22 int S, T, Maxflow, N, M;
 23 vector <int> Lv;
 24 deque <int> Q;
 25 
 26 void Init();
 27 inline void edgeAdd(int, int, int);
 28 void Dinic();
 29 bool Dinic_Label();
 30 int Dinic_Augment(int, int);
 31 void Print();
 32 void Clear();
 33 
 34 int main()
 35 {
 36     #ifdef FILE_IO
 37     freopen("1693.in", "r", stdin);
 38     #endif // FILE_IO
 39     scanf("%d%d", &N, &M);
 40     while (!(N == 0 && M == 0))
 41     {
 42         Init();
 43         Dinic();
 44         Print();
 45         Clear();
 46         scanf("%d%d", &N, &M);
 47     }
 48     #ifdef FILE_IO
 49     fclose(stdin);
 50     #endif // FILE_IO
 51     return 0;
 52 }
 53 
 54 void Init()
 55 {
 56     S = 0; T = N + 1;
 57     for (int i = 1; i <= N; i ++)
 58     {
 59         int a; scanf("%d", &a);
 60         if (a) edgeAdd(S, i, 1);
 61         else edgeAdd(i, T, 1);
 62     }
 63     for (int i = 1; i <= M; i ++)
 64     {
 65         int x, y; scanf("%d%d", &x, &y);
 66         edgeAdd(x, y, 1); edgeAdd(y, x, 1);
 67     }
 68 }
 69 
 70 inline void edgeAdd(int x, int y, int c)
 71 {
 72     E[x] = new edge(y, c, E[x]);
 73     E[y] = new edge(x, 0, E[y]);
 74     E[x] -> op = E[y]; E[y] -> op = E[x];
 75 }
 76 
 77 void Dinic()
 78 {
 79     while (Dinic_Label())
 80     {
 81         memcpy(Et, E, sizeof(Et));
 82         Maxflow += Dinic_Augment(S, INF);
 83     }
 84 }
 85 
 86 bool Dinic_Label()
 87 {
 88     Lv.assign(T + 1, -1); Lv[S] = 0;
 89     Q.clear(); Q.push_back(S);
 90     while (!Q.empty())
 91     {
 92         int i = Q.front(); Q.pop_front();
 93         for (edge* j = E[i]; j; j = j -> next)
 94         {
 95             if (j -> c && Lv[j -> v] == -1)
 96             {
 97                 Lv[j -> v] = Lv[i] + 1;
 98                 if (j -> v == T) return true;
 99                 Q.push_back(j -> v);
100             }
101         }
102     }
103     return false;
104 }
105 
106 int Dinic_Augment(int i, int bm)
107 {
108     if (i == T || bm == 0) return bm;
109     int iflow = 0;
110     for (edge* &j = Et[i]; j; j = j -> next)
111     {
112         if (j -> c && Lv[i] + 1 == Lv[j -> v])
113         {
114             int add = Dinic_Augment(j -> v, min(bm, j ->c));
115             j -> c -= add;
116             j -> op -> c += add;
117             iflow += add;
118             bm -= add;
119             if (bm == 0) break;
120         }
121     }
122     return iflow;
123 }
124 
125 void Print()
126 {
127     printf("%d\n", Maxflow);
128 }
129 
130 void Clear()
131 {
132     for (int i = 0; i <= T; i ++) E[i] = NULL;
133     Maxflow = 0;
134 }

 

 

 

转载于:https://www.cnblogs.com/GXZC/archive/2012/12/25/2832724.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值