• 【最小割二种决策选一】【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 }

     

     

  • 相关阅读:
    telent

    linux系统下部署war包
    CentOS-7.0.中安装与配置Tomcat-7的方法
    ServletContextListener
    JAVA中静态块、静态变量加载顺序详解
    git 查看父分支
    Google Guice 之绑定1
    STM32 Cubemx 配置定时器定时1mS
    项目过程的几点经验总结
  • 原文地址:https://www.cnblogs.com/GXZC/p/2832724.html
Copyright © 2020-2023  润新知