zoukankan      html  css  js  c++  java
  • [luoguP2762] 太空飞行计划问题(最大权闭合图—最小割—最大流)

    传送门

    如果将每一个实验和其所对的仪器连一条有向边,那么原图就是一个dag图(有向无环)

    每一个点都有一个点权,实验为收益(正数),仪器为花费(负数)。

    那么接下来可以引出闭合图的概念了。

    闭合图是原图的一个点集,其中这个点集中每个点的出边所指向的点依然在这个点集中,那么这个点集就是个闭合图。

    比如论文中的这个图:

    在图 3.1 中的网络有 9 个闭合图(含空集):∅,{3,4,5},{4,5},{5},{2,4,5},{2,5},{2,3,4,5},{1,2,4,5},{1,2,3,4,5}

    其中有大权和的闭合图是{3,4,5} ,权和为 4。

    显然,我们目的就是求原图中的最大权闭合图。

    为了求解这个,需要先把该图转化成网络。

    增加一个超级原点s,s与每个实验连一条权值为实验利益的边。

    增加一个超级汇点t,每个仪器与t连一条权值为仪器花费(正数)的边。

    每个实验与它所依靠的仪器连一条权值为INF的边。

    那么所有实验的费用(不是利益)减去最大流(最小割)即为最大的利益。

    为什么呢?

    根据论文中的证明,可以把最大权闭合图的问题转化为最小割。(然而看不懂)

    下面转载一段比较简单的证明(然而还是看不懂)

    首先引入结论,最小割所产生的两个集合中,其源点S所在集合(除去S)为最大权闭合图,接下来我们来说明一些结论。

    • 证明:最小割为简单割。

            引入一下简单割的概念:割集的每条边都与S或T关联。(请下面阅读时一定分清最小割与简单割,容易混淆)

            那么为什么最小割是简单割呢?因为除S和T之外的点间的边的容量是正无穷,最小割的容量不可能为正无穷。所以,得证。

    • 证明网络中的简单割与原图中闭合图存在一一对应的关系。(即所有闭合图都是简单割,简单割也必定是一个闭合图)。

            证明闭合图是简单割:如果闭合图不是简单割(反证法)。那么说明有一条边是容量为正无穷的边,则说明闭合图中有一条出边的终点不在闭合图中,矛盾。

            证明简单割是闭合图:因为简单割不含正无穷的边,所以不含有连向另一个集合(除T)的点,所以其出边的终点都在简单割中,满足闭合图定义。得正。

    • 证明最小割所产生的两个集合中,其源点S所在集合(除去S)为最大权闭合图。

            首先我们记一个简单割的容量为C,且S所在集合为N,T所在集合为M。

            则C=M中所有权值为正的点的权值(即S与M中点相连的边的容量)+N中所有权值为负的点权值的绝对值(即N中点与T中点相连边的容量)。记(C=x1+y1);(很好理解,不理解画一个图或

    想象一下就明白了)。

            我们记N这个闭合图的权值和为W。

            则W=N中权值为正的点的权值-N中权值为负的点的权值的绝对值。记(W=x2-y2);

            则W+C=x1+y1+x2-y2。

            因为明显y1=y2,所以W+C=x1+x2;

            x1为M中所有权值为正的点的权值,x2为N中权值为正的点的权值。

            所以x1+x2=所有权值为正的点的权值之和(记为TOT).

            所以我们得到W+C=TOT.整理一下W=TOT-C.

            到这里我们就得到了闭合图的权值与简单割的容量的关系。

          因为TOT为定值,所以我们欲使W最大,即C最小,即此时这个简单割为最小割,此时闭合图为其源点S所在集合(除去S)。得正。

    至此,我们就将最大权闭合图问题转化为了求最小割的问题。求最小割用最小割容量=最大流,即可将问题转化为求最大流的问题。

    转载结束。

    当然也可以这样理解,任意(非无穷大)割的值的意义都表示 实验集合中所不选的实验的利益 + 仪器集合中所选仪器的花费

    那么 所有实验的利益 - 割 = 所有实验的利益 - (实验集合中所不选的实验的利益 + 仪器集合中所选仪器的花费) = 实验集合中所选的实验的利益 - 仪器集合中所选仪器的花费 = 总利益

    要使得总利益最大,即使割最小,那么就可以通过求最小割来解决。

    至于所选的实验和仪器,只需要找最后一次增广时能够到达的点(即集合S)即可。

    ——代码

      1 #include <queue>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <iostream>
      5 #define N 3010
      6 #define min(x, y) ((x) < (y) ? (x) : (y))
      7 
      8 int n, m, sum, cnt, s, t, ans;
      9 int len[N], num[N][N], dis[N], cur[N];
     10 int head[N], next[N << 1], to[N << 1], val[N << 1];
     11 
     12 inline int read()
     13 {
     14     int x = 0, f = 1;
     15     char ch = getchar();
     16     for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
     17     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
     18     return x * f;
     19 }
     20 
     21 inline void add(int x, int y, int z)
     22 {
     23     to[cnt] = y;
     24     val[cnt] = z;
     25     next[cnt] = head[x];
     26     head[x] = cnt++;
     27 }
     28 
     29 inline bool bfs()
     30 {
     31     std::queue <int> q;
     32     memset(dis, -1, sizeof(dis));
     33     dis[s] = 0;
     34     q.push(s);
     35     int i, u, v;
     36     while(!q.empty())
     37     {
     38         u = q.front();
     39         q.pop();
     40         for(i = head[u]; i ^ -1; i = next[i])
     41         {
     42             v = to[i];
     43             if(val[i] && dis[v] == -1)
     44             {
     45                 dis[v] = dis[u] + 1;
     46                 if(v == t) return 1;
     47                 q.push(v);
     48             }
     49         }
     50     }
     51     return 0;
     52 }
     53 
     54 inline int dfs(int u, int maxflow)
     55 {
     56     if(u == t) return maxflow;
     57     int i, v, d, ret = 0;
     58     for(i = cur[u]; i ^ -1; i = next[i])
     59     {
     60         v = to[i];
     61         if(val[i] && dis[v] == dis[u] + 1)
     62         {
     63             d = dfs(v, min(val[i], maxflow - ret));
     64             ret += d;
     65             val[i] -= d;
     66             val[i ^ 1] += d;
     67             cur[u] = i;
     68             if(ret == maxflow) return ret;
     69         }
     70     }
     71     return ret;
     72 }
     73 
     74 int main()
     75 {
     76     int i, j, x, l;
     77     std::string S;
     78     m = read();
     79     n = read();
     80     s = 0, t = n + m + 1;
     81     memset(head, -1, sizeof(head));
     82     for(i = 1; i <= m; i++)
     83     {
     84         x = read();
     85         add(s, i, x); 
     86         add(i, s, 0);
     87         sum += x;
     88         getline(std::cin, S);
     89         l = S.length();
     90         for(j = 0; j < l; j++)
     91         {
     92             x = 0;
     93             if(S[j] == ' ') continue;
     94             while(isdigit(S[j]))
     95             {
     96                 x = (x << 1) + (x << 3) + S[j] - '0';
     97                 j++;
     98             }
     99             num[i][++len[i]] = x;
    100         }
    101         for(j = 1; j <= len[i]; j++)
    102             add(i, num[i][j] + m, 1e9), add(num[i][j] + m, i, 0);
    103     }
    104     for(i = 1; i <= n; i++)
    105     {
    106         x = read();
    107         add(i + m, t, x);
    108         add(t, i + m, 0);
    109     }
    110     while(bfs())
    111     {
    112         for(i = s; i <= t; i++) cur[i] = head[i];
    113         ans += dfs(s, 1e9);
    114     }
    115     for(i = 1; i <= m; i++)
    116         if(dis[i] ^ -1)
    117             printf("%d ", i);
    118     puts("");
    119     for(i = 1; i <= n; i++)
    120         if(dis[i + m] ^ -1)
    121             printf("%d ", i);
    122     puts("");
    123     printf("%d
    ", sum - ans);
    124     return 0;
    125 }
    View Code

    转载内容来自:http://www.cnblogs.com/wuyiqi/archive/2012/03/12/2391960.html

    参考:胡伯涛 《最小割模型在信息学竞赛中的应用》


     

  • 相关阅读:
    linux学习 建立静态库,动态库,写简单的makefile
    C++中顶层const和底层const
    BDB (Berkeley DB)数据库简单介绍(转载)
    Java中Map的使用
    Spring MVC 3 深入总结
    nvl,空时的推断和取值
    java堆栈 (转)
    mybatis--面向接口编程
    HDU 4888
    socket编程——一个简单的样例
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/6929083.html
Copyright © 2011-2022 走看看