zoukankan      html  css  js  c++  java
  • [上下界网络流][二分] Bzoj P2406 矩阵

    题目描述

    输入输出格式

    输入格式:

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

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

    最后一行两个数L,R。

    输出格式:

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

    输入输出样例

    输入样例#1:
    2 2
    0 1
    2 1
    0 1
    输出样例#1:
    1

    说明

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

    题解

    • 这题的转换实在是太TM的神奇了!!!
    • 首先,题目要求的其实是最大值最小,那么我们可以二分,将其转换为判断性问题
    • 乍一看这个式子,一脸懵逼,再乍一看,其实就是要我们“最小化每行每列所有元素与给定矩阵差的和的绝对值中的最大值”
    • 然后先设h[i]为第i行的和,l[i]为第i列的和
    • 那么如果要满足二分出来的mid,那么一定要满足B矩阵的第i行总和为[r[i]-mid,mid+r[i]],同列的话也是一样的
    • 那么我们就可以把每列每行的看成一个点,原点向每个行点连边,上下界为[r[i]-mid,mid+r[i]],列点向汇点连边,上下界为[c[i]-mid,mid+c[i]]
    • 然后行列之间连边上下界为[L,R],这样的话,问题就可以转换为是否存在二分图中是否存在一个可行流
    • 那么跑一遍上下界网络流就好了

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <queue>
     5 #include <algorithm>
     6 using namespace std;
     7 const int N=510;
     8 const int inf=0x3f3f3f3f;
     9 int n,m,cnt,s,t,S,T,head[N],dis[N],cur[N],d[N],h[N],l[N],L,R,num[N][N];
    10 struct edge{int to,from,v;}e[N*N*2];
    11 queue<int> Q;
    12 void insert(int x,int y,int v)
    13 {
    14     e[++cnt].to=y,e[cnt].from=head[x],e[cnt].v=v,head[x]=cnt;
    15     e[++cnt].to=x,e[cnt].from=head[y],e[cnt].v=0,head[y]=cnt;
    16 }
    17 int dfs(int x,int maxf)
    18 {
    19     if (x==T||!maxf) return maxf;
    20     int ret=0;
    21     for (int &i=cur[x];i;i=e[i].from)
    22         if (e[i].v&&dis[e[i].to]==dis[x]+1)
    23         {
    24             int f=dfs(e[i].to,min(e[i].v,maxf-ret));
    25             e[i].v-=f,e[i^1].v+=f,ret+=f;
    26             if (maxf==ret) break;
    27         }
    28     return ret;
    29 }
    30 bool bfs()
    31 {
    32     for (int i=s;i<=T;i++) dis[i]=0;
    33     while (!Q.empty()) Q.pop();
    34     dis[S]=1,Q.push(S);
    35     while (!Q.empty())
    36     {
    37         int u=Q.front(); Q.pop();
    38         for (int i=head[u];i;i=e[i].from)
    39             if (e[i].v&&!dis[e[i].to])
    40             {
    41                 dis[e[i].to]=dis[u]+1;
    42                 if (e[i].to==T) return 1;
    43                 Q.push(e[i].to);
    44             }
    45     }
    46     return 0;
    47 }
    48 int dinic()
    49 {
    50     int ans=0;
    51     while (bfs())
    52     {
    53         for (int i=0;i<=T;i++) cur[i]=head[i];
    54         ans+=dfs(S,inf);
    55     }
    56     return ans;
    57 }
    58 bool check(int x)
    59 {
    60     cnt=1,memset(d,0,sizeof(d)),memset(head,0,sizeof(head)),s=0,t=n+m+1,S=n+m+2,T=n+m+3;
    61     insert(t,s,inf);
    62     for (int i=1;i<=n;i++)
    63         for (int j=1;j<=m;j++)
    64             insert(i,j+n,R-L),d[i]-=L,d[j+n]+=L,num[i][j]=cnt;
    65     for (int i=1;i<=n;i++)
    66     {
    67         int p=max(0,h[i]-x),q=x+h[i];
    68         insert(s,i,q-p),d[s]-=p,d[i]+=p;
    69     }
    70     for (int i=1;i<=m;i++)
    71     {
    72         int p=max(0,l[i]-x),q=x+l[i];
    73         insert(i+n,t,q-p),d[i+n]-=p,d[t]+=p;
    74     }
    75     int tot=0;
    76     for (int i=s;i<=t;i++) if (d[i]>0) insert(S,i,d[i]),tot+=d[i]; else if (d[i]<0) insert(i,T,-d[i]);
    77     return dinic()==tot;
    78 }
    79 int main()
    80 {
    81     scanf("%d%d",&n,&m);
    82     for (int i=1,x;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&x),h[i]+=x,l[j]+=x;
    83     scanf("%d%d",&L,&R);
    84     int l=0,r=200000;
    85     while (l<=r)
    86     {
    87         int mid=l+r>>1;
    88         if (check(mid)) r=mid-1; else l=mid+1;
    89     }
    90     printf("%d",r+1);
    91 }
  • 相关阅读:
    互联网产品的灰度发布
    丰网速运单号查询快递鸟API接口-丰网速运
    电商系统物流管理之逆向物流退换货流程设计
    用JS进行Base64编码,MD5加密,实现签名验证 调用快递鸟API接口 完成快递单号查询 JavaScript
    京东快递上门取件接口-快递鸟在线下单API
    申通快递上门取件接口-快递鸟在线下单API
    极兔快递电子面单打印API接口-极兔速递
    电子面单模板规格汇总-快递鸟
    澳邮快递单号查询接口-快递鸟API 澳邮中国
    光线速递快递单号查询接口-快递鸟API
  • 原文地址:https://www.cnblogs.com/Comfortable/p/10304186.html
Copyright © 2011-2022 走看看