zoukankan      html  css  js  c++  java
  • bzoj网络流

    近期看了一些bzoj的网络流,深感智商不够。不过对于网络流又有了进一步的理解。

    还是mark一下吧。

    献上几篇论文:1)最小割模型在信息学竞赛中的应用》

                        2)《浅析一类最小割问题》

    1、bzoj1066(最大流)

    题意:戳这里

    思路:很明显拆点最大流模型,然后对于每个点每个高度流量限为1,那么根据最大流即为可以出去的蜥蜴的数量。

    2、bzoj1077(费用流)

    戳这里

    3.bzoj1391(最小割)

    题意:戳这里

    思路:有点像最大权闭合图。。可以利用最小割的性质建图:

            <S,任务,收益>

            <机器,T,购买费用>,<任务,机器,租用费用>

            这样,如果与T相连的边为割,表示购买机器花费更小。

            如果与S相连的边为割,表示任务花费太大,不做任务更优(收益为0)。

            如果<任务,机器>边为割,表示任务花费太大,不做任务更优(收益为0)。

            最后总收益-最大流即为答案

    4、bzoj1412(最小割)

    题意:有一些格子里是狼,一些里是羊,一些是空的,要使狼和羊的格子不相通,至少要堵多少条边界。

    思路:很明显的最小割

    5、bzoj1433(二分图匹配)

    题意:戳这里

    思路:需要床位的为一边,提供床位的为一边,认识连一条边(包括自己跟自己),然后就是一个二分图最大匹配。

    6、bzoj1475(最大点独立集)

    题意:戳这里

    思路:Amber论文里讲到的题目,很明显可以看出是个二分图模型。。

            但是不容易看出是求最大点权独立集。那么构图就很显然了。

    7、bzoj1497(最大密度子图)

    题意:戳这里

    思路:可以转化成最小割。具体看Amber论文。

    8、bzoj1520(费用流)

    题意:戳这里

    思路:很明显的最小费用流

    9、bzoj1532(最大流+二分)

    题意:戳这里

    思路:二分最大分数score,那么

            <S,人,score>,<人,比赛,1>,<比赛,T,1>

            判断流量flow = m

    10、bzoj1565(tarjan+最大权闭合图)

    题意:戳这里

    思路:首先先把保护关系建立有向边,那么如果出现环的话,环里面的所有点,包括他能保护得点都不能取。。

             那么剩下的图再进行最大权闭合图的构图

    code:

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 #define M0(a) memset(a, 0, sizeof(a))
      4 #define Inf 0x3fffffff
      5 const int maxn = 1000;
      6 const int maxm = 800010;
      7 struct oo{
      8     int y, f, next;
      9 };
     10 struct MaxFlow{
     11        int n, S, T, tot;
     12        int son[maxn], dist[maxn], gap[maxn];
     13        oo e[maxm];
     14        int sap(int x, int aug){
     15            if (x == T) return aug;
     16            int mind = n;
     17            int sum = 0, f;
     18            for (int p = son[x]; p != -1; p = e[p].next){
     19                   int y = e[p].y;
     20                   if (dist[y] + 1 == dist[x] && e[p].f){
     21                        f = sap(y, min(e[p].f, aug - sum));
     22                        e[p].f -= f;
     23                        e[p^1].f += f;
     24                        sum += f;
     25                        if (sum == aug || dist[S] >= n) return sum;
     26                   }
     27                   if (e[p].f) mind = min(mind, dist[y]);
     28            }
     29            if (!sum){
     30                if (!(--gap[dist[x]])) dist[S] = n;
     31                ++gap[dist[x] = mind + 1];
     32            }
     33            return sum;
     34        }
     35        void add(int x, int y, int f){
     36             e[tot].y = y; e[tot].f = f;
     37             e[tot].next = son[x]; son[x] = tot++;
     38             e[tot].y = x; e[tot].f = 0;
     39             e[tot].next = son[y]; son[y] = tot++;
     40        }
     41 
     42        void init(int S, int T, int n){
     43             memset(son, -1, sizeof(son));
     44             tot = 0;
     45             this->S = S, this->T = T, this->n = n;
     46        }
     47        int maxflow(){
     48             M0(gap);
     49             M0(dist);
     50             gap[0] = n;
     51             int ans = 0;
     52             while (dist[S] < n) ans += sap(S, Inf);
     53             return ans;
     54        }
     55 } F;
     56 vector<int> e[maxn];
     57 int n, m, sum;
     58 int score[31][31], use[31 * 31], vis[31 * 31];
     59 //vector<pair<int, int> > pre[35][35]; 
     60 void init(){
     61      for (int i = 0; i <= n * m; ++i)
     62            e[i].clear();
     63 //     for (int i = 0; i <= n; ++i)
     64 //         for ()
     65      int k, x, y;
     66      int cur = 0;
     67      for (int i = 1; i <= n; ++i)
     68          for (int j = 1; j <= m; ++j){
     69               scanf("%d%d", &score[i][j], &k);
     70               ++cur;
     71               while (k--){
     72                    scanf("%d%d", &x, &y);
     73                    e[cur].push_back(x*m+y+1);
     74               }
     75               if (j > 1) e[cur].push_back(cur-1);
     76          }
     77         
     78 }
     79 /*** tarjan-begin ***/
     80 int top, Index, dfn[maxn], low[maxn], stk[maxn], col[maxn], cnt;
     81 bool insta[maxn];
     82 vector<int> co[maxn];
     83 void tarjan(int u){
     84     dfn[u] = low[u] = ++Index;
     85     stk[++top] = u;
     86     insta[u] = true;
     87     int v;
     88     for (int i = 0; i < (int)e[u].size(); ++i){
     89         v = e[u][i];
     90         if (!dfn[v]){
     91             tarjan(v);
     92             low[u] = min(low[v], low[u]);   
     93         } 
     94         else if (insta[v]) low[u] = min(low[u], dfn[v]);
     95     }
     96     if (dfn[u] == low[u]){
     97         ++cnt;
     98         while (1){
     99             col[stk[top]] = cnt;
    100             insta[stk[top]] = false;
    101             if (stk[top--] == u) break;    
    102         }        
    103     }
    104 }
    105 
    106 void tarjan(){
    107     M0(dfn), M0(low), M0(insta), M0(col);
    108     top = cnt = Index = 0;
    109     for (int i = 1; i <= n*m; ++i)
    110         if (!dfn[i]) tarjan(i);
    111     for (int i = 1; i <= n * m; ++i)
    112          co[i].clear();
    113     for (int i = 1; i <= n * m; ++i)
    114          co[col[i]].push_back(i);
    115 }
    116 /***tarjan-end ***/
    117 
    118 void dfs(const int u){
    119     if (vis[u]) return;
    120     vis[u] = 1;
    121     for (int i = 0; i < (int)e[u].size(); ++i)
    122           dfs(e[u][i]);
    123 }
    124 
    125 void solve(){
    126      tarjan();
    127      M0(use);
    128      for (int i = 1; i <= cnt; ++i)
    129          if ((int)co[i].size() > 1){
    130                 for (int j = 0; j < (int)co[i].size(); ++j)
    131                   use[co[i][j]] = 1;
    132          }
    133      M0(vis);
    134      for (int i = 1; i <= n * m; ++i)
    135          if (use[i] && !vis[i]) dfs(i);
    136      int S = 0, T = n *m + 1;
    137      F.init(S, T, T + 1);
    138      int cur = sum = 0;
    139      for (int i = 1; i <= n; ++i)
    140           for (int j = 1; j <= m; ++j){
    141                ++cur;
    142                if (vis[cur]) continue; 
    143                if (score[i][j] >= 0) 
    144                       F.add(S, cur, score[i][j]), sum += score[i][j];
    145                else
    146                       F.add(cur, T, -score[i][j]); 
    147                for (int k = 0; k < (int)e[cur].size(); ++k)
    148                       F.add(e[cur][k], cur, Inf);
    149           }
    150      int ans = sum - F.maxflow();
    151      printf("%d
    ", ans);
    152 }
    153 
    154 int main(){
    155 //     freopen("a.in", "r", stdin);
    156      while (scanf("%d%d", &n, &m) != EOF){
    157           init();
    158           solve();     
    159      }
    160 }
    View Code

    11、bzoj1585(最小割)

    题意:戳这里

    思路:

    拆点最小割,保证每个点流量为1

    <S, 1, INF>

    提到的点x : <x', T, INF>

    对于每个点x,为1或是提到的点: <x,x',INF>

    对于每个点x,不为1且不是提到的点:<x,x',1>

    对于原图每条边x->y: <x', y, INF>和 <y', x, INF>

    最大流即为答案。。

    ps..这一题跟usaco原题改动有点大。。害我做原题时进坑了。。

    12、bzoj1711(最大流)

    题意:戳这里

    思路:三分图匹配,记得中间那个点要拆点限流量为1

    13、bzoj1741(最小点覆盖)

    题意:戳这里

    思路:把行列抽象出来成为一个二分图,有小行星就连一条边。那么题目就等价与求出最小的点覆盖所有的遍。

    14、bzoj1779(拆点最大流)

    题意:戳这里

    思路:好像还不是很理解。。过后补上。

    15、bzoj1797(最小割+tarjan)

    题意:戳这里

    思路:首先跑一边最大流。然后在残余图中进行tarjan缩点。

             那么对于所有满流边:

                  如果连接S,T两个强联通分量,那么一定是在最小割里。

                  如果连接两个不同的强联通分量,可能出现在最小割里。

    16、bzoj1822(二分+最大流)

    题意:戳这里

    思路:二分时间t,那么就可以算出在这个时间内每个巫妖可以攻击的数目。

             然后建图:

             <S,  巫妖, 可攻击数目>,<巫妖,可攻击到的小精灵, 1>,<小精灵, T , 1>

              最后判断最大流是否为小精灵个数

              比较麻烦的是判断巫妖是否攻击到小精灵,需要一点计算几何知识。

    17、bzoj1834(网络流模板)

    题意:戳这里

    思路:<S, 1, K>, 先跑一边最大流,然后在残余网络的每条边加上一条流量Inf费用为扩容费用的边

    18、bzoj1877(最小费用最大流)

    题意:戳这里

    思路:拆点,然后就是经典构图了

    19、bzoj1927(最小费用最大流)

    戳这里

    20、bzoj1934(最小割)

    题意:戳这里

    思路:分集合很典型的最小割的应用

             最初选择睡午觉 <S, i, 1>

             最初选择不睡午觉 <i, T, 1>

             i与j为好友, <i, j, 1> <j, i, 1> 

             最小割即为答案。。这应该是pty大神论文最简单的应用吧

    21、bzoj1937(二分图最大权匹配问题)

    题意:戳这里

    思路:把所有边分为树边与非树边,那么对于费树边i,连接u,v

             权值wi>=wj(所有u,v路径上的边j),所以非树边只有可能变大,树边只有可能变小

             即,对于非树边i即路径上的任意树边j:

                  wi + di >= wj - dj

             => di + dj >= wj - wi

            wj-wi为定值,那么等式几乎就跟最大权匹配的顶标的式子一样了。。

             套用最大权匹配km算法。。

            本来想用费用流,一想到边很多就怂了。。

    22、bzoj2039(最小割)

    戳这里

    23、bzoj2127(最小割)

    题意:戳这里

    思路:可利用二元关系建图:

             <S, A, w1/2>,<A, T, w2/2>

            <S, B, w1/2> , <B,T,w2/2>,

             <A, B, (w1+w2)/2>, <B, A, (w1 + w2)/2>

           为防止出现小数,可将所有流量都流量*2,最后/2即可。

            答案即为sum(喜悦值)- flow

    未完待续。。。

  • 相关阅读:
    keepalived 结合mysql 自动切换
    haproxy 配置日志
    haproxy 配置日志
    keepalive的 nopreempt 非抢占
    keepalive的 nopreempt 非抢占
    keepavlied一些参数
    keepavlied一些参数
    mysql 结合keepalived测试
    【转载】[小红猪]11个物理难题,11种基本粒子 分类: 生活百科 2013-07-26 11:04 317人阅读 评论(0) 收藏
    【转载】上帝粒子证实存在宇宙末日来临?(图) 分类: 生活百科 2013-07-26 11:04 336人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/yzcstc/p/4055317.html
Copyright © 2011-2022 走看看