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 }
  • 相关阅读:
    PAT (Basic Level) Practise 1013 数素数
    PAT (Basic Level) Practise 1014 福尔摩斯的约会
    codeforces 814B.An express train to reveries 解题报告
    KMP算法
    rsync工具
    codeforces 777C.Alyona and Spreadsheet 解题报告
    codeforces 798C.Mike and gcd problem 解题报告
    nginx + tomcat多实例
    MongoDB副本集
    指针的艺术(转载)
  • 原文地址:https://www.cnblogs.com/Comfortable/p/10304186.html
Copyright © 2011-2022 走看看