【上下界网络流 二分】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\n",ans);
121     return 0;
122 }

 

 

 

 

END

posted @ 2019-02-11 19:34  AntiQuality  阅读(162)  评论(0编辑  收藏  举报