• 【上下界网络流 二分】bzoj2406: 矩阵


    感觉考试碰到上下界网络流也还是写不来啊

    Description

    Input

    第一行两个数n、m,表示矩阵的大小。

    接下来n行,每行m列,描述矩阵A。

    最后一行两个数L,R。

    Output

    第一行,输出最小的答案;

    HINT

    对于100%的数据满足N,M<=200,0<=L<=R<=1000,0<=Aij<=1000


    题目分析

    首先二分行列之差的最大值。

    这一类行列上的问题,属于经典的网络流模型。将行列各自看成点,由S向这些点连容量为$[ΣA_{i,j}-x,ΣA_{i,j}+x]$的边,再在行列之间互相连$[L,R]$的边,那么最终每个点的流量就是其行/列的权值和。

    于是问题就变成了判定有源汇上下界可行流

      1 #include<bits/stdc++.h>
      2 const int maxn = 435;
      3 const int maxm = 500035;
      4 const int INF = 2e9;
      5 
      6 struct Edge
      7 {
      8     int u,v,f,c;
      9     Edge(int a=0, int b=0, int c=0, int d=0):u(a),v(b),f(c),c(d) {}
     10 }edges[maxm];
     11 int edgeTot,head[maxn],nxt[maxm],lv[maxn],cur[maxn];
     12 int r[maxn],c[maxn],a[maxn][maxn];
     13 int n,m,S,T,SS,TT,lLim,rLim,ans;
     14 
     15 int read()
     16 {
     17     char ch = getchar();
     18     int num = 0, fl = 1;
     19     for (; !isdigit(ch); ch=getchar())
     20         if (ch=='-') fl = -1;
     21     for (; isdigit(ch); ch=getchar())
     22         num = (num<<1)+(num<<3)+ch-48;
     23     return num*fl;
     24 }
     25 void addedge(int u, int v, int c)
     26 {
     27     edges[edgeTot] = Edge(u, v, 0, c), nxt[edgeTot] = head[u], head[u] = edgeTot++;
     28     edges[edgeTot] = Edge(v, u, 0, 0), nxt[edgeTot] = head[v], head[v] = edgeTot++;
     29 }
     30 bool buildLevel()
     31 {
     32     std::queue<int> q;
     33     memset(lv, 0, sizeof lv);
     34     lv[S] = 1, q.push(S);
     35     for (int i=1; i<=TT; i++) cur[i] = head[i];
     36     for (int tmp; q.size(); )
     37     {
     38         tmp = q.front(), q.pop();
     39         for (int i=head[tmp]; i!=-1; i=nxt[i])
     40         {
     41             int v = edges[i].v;
     42             if (!lv[v]&&edges[i].f < edges[i].c){
     43                 lv[v] = lv[tmp]+1, q.push(v);
     44                 if (v==T) return true;
     45             }
     46         }
     47     }
     48     return false;
     49 }
     50 int fndPath(int x, int lim)
     51 {
     52     if (x==T) return lim;
     53     for (int &i=cur[x]; i!=-1; i=nxt[i])
     54     {
     55         int v = edges[i].v, val;
     56         if (lv[x]+1==lv[v]&&edges[i].f < edges[i].c){
     57             if ((val = fndPath(v, std::min(lim, edges[i].c-edges[i].f)))){
     58                 edges[i].f += val, edges[i^1].f -= val;
     59                 return val;
     60             }else lv[v] = -1;
     61         }
     62     }
     63     cur[x] = head[x];
     64     return 0;
     65 }
     66 int dinic()
     67 {
     68     int ret = 0, val;
     69     while (buildLevel())
     70         while ((val = fndPath(S, INF))) ret += val;
     71     return ret;
     72 }
     73 bool check(int x)
     74 {
     75     int cur = 0;
     76     memset(head, -1, sizeof head);
     77     edgeTot = 0;
     78     for (int i=1; i<=n; i++)
     79     {
     80         if (r[i]+x < 0) return false;
     81         if (r[i]-x > 0){
     82             addedge(SS, T, r[i]-x);
     83             addedge(S, i, r[i]-x);
     84             addedge(SS, i, x<<1);
     85             cur += r[i]-x;
     86         }else addedge(SS, i, r[i]+x);
     87     }
     88     for (int i=1; i<=m; i++)
     89     {
     90         if (c[i]+x < 0) return false;
     91         if (c[i]-x > 0){
     92             addedge(S, TT, c[i]-x);
     93             addedge(i+n, T, c[i]-x);
     94             addedge(i+n, TT, x<<1);
     95             cur += c[i]-x;
     96         }else addedge(i+n, TT, c[i]+x);
     97     }
     98     for (int i=1; i<=n; i++)
     99         for (int j=1; j<=m; j++)
    100             addedge(i, j+n, rLim);
    101     addedge(TT, SS, INF);
    102     return cur==dinic();
    103 }
    104 int main()
    105 {
    106     n = read(), m = read();
    107     S = n+m+1, T = S+1, SS = T+1, TT = SS+1;
    108     for (int i=1; i<=n; i++)
    109         for (int j=1; j<=m; j++)
    110             a[i][j] = read();
    111     lLim = read(), rLim = read();
    112     for (int i=1; i<=n; i++)
    113         for (int j=1; j<=m; j++)
    114             a[i][j] -= lLim, r[i] += a[i][j], c[j] += a[i][j];
    115     rLim -= lLim;
    116     int L = 0, R = std::max(*std::max_element(r+1, r+n+1), *std::max_element(c+1, c+m+1));
    117     for (int mid=(L+R)>>1; L<=R; mid=(L+R)>>1)
    118         if (check(mid)) ans = mid, R = mid-1;
    119         else L = mid+1;
    120     printf("%d
    ",ans);
    121     return 0;
    122 }

     

     

     

    END

  • 相关阅读:
    菜鸟也为Git疯狂
    C#实现简单的栈和队列
    Entity Framework模型在领域驱动设计界定上下文中的应用
    SQL 关于使用CTE
    《高效程序员的45个习惯》读书笔记
    开源.NET下的XML数据库介绍及入门
    openkm开发环境搭建过程
    ASP.NET MVC+EF框架+EasyUI实现权限管理系列之开篇
    《Clean Code》Learning
    网络抓包工具 Network Monitor使用方法 Fiddler使用方法
  • 原文地址:https://www.cnblogs.com/antiquality/p/10362960.html
Copyright © 2020-2023  润新知