zoukankan      html  css  js  c++  java
  • 【思维题 费用流 技巧】bzoj5403: marshland

    主要还是网络流拆点建图一类技巧吧

    Description

    第一眼看到这题时候只会把每个点拆成4个方向;再强制定向连边防止成环;最后做一遍最大费用可行流。

    然而这种做法显然比较复杂,且关于强制定向我也并不是很熟练……

    再仔细研究一下题目的性质,发现危险度所处的格子奇偶性是相同的。这种性质使得我们可以以黑白染色的角度考虑强制定向的问题。

    设$X+Y$为奇数的点为黑点;为偶数的点为白点。那么“折形”的限制就表述为每当选了一个黑点,就在上下、左右各选一个白点相连。对于费用流的建模,我们可以看做黑点放在中间,上下的白点在左边连向黑点;左右的白点在右边与黑点相连。首先来看中间的黑点,为了从费用流角度表示选取黑点,当然就是拆点连费用为$v[i][j]$的边。再是黑点两侧的点,需要注意的有:一、此处只是表示出了全图的一个部分,这里的白点还会和其他黑点产生关系,因此“两侧”的白点区别应当从所属行的奇偶性考虑。二、既然已经对黑点强制定向,那么“两侧”的白点就当分类分别处理与$S,T$的连边。

    从这个角度建模后,由于对于每一个黑点都有关于相邻白点的$S,T$通路,那么每增广一次必然是在最大流的前提下保证选了当前最大费用。之所以提这一点,是因为有一些不恰当的建图方式把以S为起点的拓扑序安排得很混乱,以至于各个危险点之间的选取并不是完全分离的过程。

    那么,剩下的就是一遍最大费用可行流的事情了。

     1 #include<bits/stdc++.h>
     2 typedef long long ll;
     3 const int maxn = 53;
     4 const int maxNode = 5035;
     5 const int maxm = 500035;
     6 const int INF = 2e9;
     7 
     8 struct Edge
     9 {
    10     int u,v,f,c,cst;
    11     Edge(int a=0, int b=0, int c=0, int d=0, int e=0):u(a),v(b),f(c),c(d),cst(e) {}
    12 }edges[maxm];
    13 int n,lim,k,S,T;
    14 int id[maxn][maxn],v[maxn][maxn];
    15 int edgeTot,head[maxNode],nxt[maxm],bck[maxNode],flw[maxNode];
    16 ll ans,cst[maxNode];
    17 bool inq[maxNode],chk;
    18 
    19 int read()
    20 {
    21     char ch = getchar();
    22     int num = 0, fl = 1;
    23     for (; !isdigit(ch); ch=getchar())
    24         if (ch=='-') fl = -1;
    25     for (; isdigit(ch); ch=getchar())
    26         num = (num<<1)+(num<<3)+ch-48;
    27     return num*fl;
    28 }
    29 void addedge(int u, int v, int c, int cst)
    30 {
    31     edges[edgeTot] = Edge(u, v, 0, c,  cst), nxt[edgeTot] = head[u], head[u] = edgeTot, ++edgeTot;
    32     edges[edgeTot] = Edge(v, u, 0, 0, -cst), nxt[edgeTot] = head[v], head[v] = edgeTot, ++edgeTot;
    33 }
    34 void maxFlow()
    35 {
    36     std::queue<int> q;
    37     memset(bck, 0, sizeof bck);
    38     memset(flw, 0, sizeof flw);
    39     memset(cst, -0x3f3f3f3f, sizeof cst);
    40     q.push(S), flw[S] = INF, cst[S] = 0;
    41     for (int tmp; q.size(); )
    42     {
    43         tmp = q.front(), q.pop(), inq[tmp] = 0;
    44         for (int i=head[tmp]; i!=-1; i=nxt[i])
    45         {
    46             int v = edges[i].v;
    47             if (cst[tmp]+edges[i].cst > cst[v]&&edges[i].f < edges[i].c){
    48                 cst[v] = cst[tmp]+edges[i].cst, bck[v] = i;
    49                 flw[v] = std::min(flw[tmp], edges[i].c-edges[i].f);
    50                 if (!inq[v]) inq[v] = 1, q.push(v);
    51             }
    52         }
    53     }
    54     if (cst[T] < 0) chk = false;
    55     else{
    56         for (int i=T; i!=S; i=edges[bck[i]].u)
    57             edges[bck[i]].f += flw[T], edges[bck[i]^1].f -= flw[T];
    58         ans -= cst[T]*flw[T];
    59     }
    60 }
    61 int main()
    62 {
    63     memset(head, -1, sizeof head);
    64     n = read(), lim = read(), k = read();
    65     S = 0, T = n*n*2+1;
    66     for (int i=1, cnt=0; i<=n; i++)
    67         for (int j=1; j<=n; j++)
    68             id[i][j] = ++cnt, v[i][j] = read(), ans += v[i][j];
    69     for (; k; --k) v[read()][read()] = INF;
    70     for (int i=1; i<=n; i++)
    71         for (int j=1; j<=n; j++)
    72             if (v[i][j]!=INF){
    73                 if ((i+j)&1) addedge(id[i][j], id[i][j]+n*n, 1, v[i][j]);
    74                 else{
    75                     if (i&1){
    76                         addedge(S, id[i][j], 1, 0);
    77                         if (i > 1) addedge(id[i][j], id[i-1][j], 1, 0);
    78                         if (i < n) addedge(id[i][j], id[i+1][j], 1, 0);
    79                         if (j > 1) addedge(id[i][j], id[i][j-1], 1, 0);
    80                         if (j < n) addedge(id[i][j], id[i][j+1], 1, 0);
    81                     }else{
    82                         addedge(id[i][j], T, 1, 0);
    83                         if (i > 1) addedge(id[i-1][j]+n*n, id[i][j], 1, 0);
    84                         if (i < n) addedge(id[i+1][j]+n*n, id[i][j], 1, 0);
    85                         if (j > 1) addedge(id[i][j-1]+n*n, id[i][j], 1, 0);
    86                         if (j < n) addedge(id[i][j+1]+n*n, id[i][j], 1, 0);
    87                     }
    88                 }
    89             }
    90     chk = true;
    91     for (; lim&&chk; --lim) maxFlow();
    92     printf("%lld
    ",ans);
    93     return 0;
    94 }

    END

  • 相关阅读:
    大数乘法
    大数阶乘
    存js导入excel文件
    设计模式详解
    javascript的api设计原则
    从零开始nodejs系列文章
    git的学习
    如何暴力学英语
    Vsftpd
    shell命令学习
  • 原文地址:https://www.cnblogs.com/antiquality/p/10519336.html
Copyright © 2011-2022 走看看