• bzoj 2406: 矩阵 ——solution


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

    http://www.lydsy.com/JudgeOnline/problem.php?id=2406



    题中式的含义为构造B矩阵

    使得

    B中每个元素在LR之间

    且矩阵(A-B)的每一行的和的绝对值与每一列的和的绝对值构成的数集

    最大值最小;

    考虑枚举这个数集的上界;

    这个可以二分;

    当我们二分到一个上界后,考虑如何check;

    check的过程实则是找到一组满足所有限制的解

    可以用经典的行列间连边的网络流模型的有上下界版本来做;

    建图为:
    有n个点代表n行,m个点代表m列;

    每行向每列连上界R下界L的边——表示B中每个点的大小限制;

    S向每行连上界(A该行和+二分值)下界(A该行和-二分值)的边——表示当B的这一行和最大时,B这行和-A这行和不大于二分值;当B的这一行和最小时,A这行和-B这行和不大于二分值(列出式子化化看)

    每行向T同理;

    然后T向S连INF,产生循环流;

    然后产生S’和T’将原图改成能通跑最大流得出可行流的新图,跑一跑,看看是否有可行流;

    代码:

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 using namespace std;
      5 const int INF=0x3f3f3f3f;
      6 int L,R,N,M;
      7 int S,T,MD;
      8 int A[210][210];
      9 int sum_x[210],sum_y[210];
     10 struct ss{
     11     int to,next,f,cp;
     12 }e[200010];
     13 int first[1000],num,cut[1000],dep[1000],que[10000];
     14 int lim_line[1000];
     15 bool check(int );
     16 void bui_(int ,int ,int );
     17 void build(int ,int ,int );
     18 bool bfs();
     19 int dfs(int ,int );
     20 int main()
     21 {
     22     int i,j,k,l,r,mid;
     23     scanf("%d%d",&N,&M);
     24     for(i=1;i<=N;i++)
     25         for(j=1;j<=M;j++)
     26             scanf("%d",&A[i][j]),sum_x[i]+=A[i][j],sum_y[j]+=A[i][j];
     27     scanf("%d%d",&L,&R);
     28     l=0,r=200000,mid=(l+r)>>1;
     29     while(r-l>3){
     30         if(check(mid))
     31             r=mid;
     32         else
     33             l=mid+1;
     34         mid=(l+r)>>1;
     35     }
     36     for(mid=l;mid<=r;mid++)
     37         if(check(mid)){
     38             printf("%d
    ",mid);
     39             return 0;
     40         }
     41     return 0;
     42 }
     43 bool check(int lim){
     44     int i,j,k,ans=0,add;
     45     memset(first,0,sizeof(first)),num=0;
     46     memset(lim_line,0,sizeof(lim_line));
     47     MD=N+M+1;
     48     S=MD+1,T=S+1;
     49     for(i=1;i<=N;i++){
     50         j=max(0,sum_x[i]-lim);
     51         k=sum_x[i]+lim;
     52         lim_line[MD]-=j;
     53         lim_line[i]+=j;
     54         bui_(MD,i,k-j);
     55     }
     56     for(i=1;i<=M;i++){
     57         j=max(0,sum_y[i]-lim);
     58         k=sum_y[i]+lim;
     59         lim_line[MD]+=j;
     60         lim_line[i+N]-=j;
     61         bui_(i+N,MD,k-j);
     62     }
     63     for(i=1;i<=N;i++)
     64         for(j=1;j<=M;j++){
     65             lim_line[i]-=L;
     66             lim_line[j+N]+=L;
     67             bui_(i,j+N,R-L);
     68         }
     69     for(i=1;i<=MD;i++)
     70         if(lim_line[i]){
     71             if(lim_line[i]>0)bui_(S,i,lim_line[i]),ans+=lim_line[i];
     72             else             bui_(i,T,-lim_line[i]);
     73         }
     74     while(bfs())
     75         while(add=dfs(S,INF))
     76             ans-=add;
     77     return !ans;
     78 }
     79 void bui_(int f,int t,int fi){
     80     build(f,t,fi),e[num].cp=num+1;
     81     build(t,f,0),e[num].cp=num-1;
     82 }
     83 void build(int f,int t,int fi){
     84     e[++num].next=first[f];
     85     e[num].to=t,e[num].f=fi;
     86     first[f]=num;
     87 }
     88 bool bfs(){
     89     int i,h=0,t=1;
     90     memset(dep,0,sizeof(dep));
     91     for(i=1;i<=T;i++)cut[i]=first[i];
     92     que[t]=S,dep[S]=1;
     93     while(h<t){
     94         h++;
     95         for(i=first[que[h]];i;i=e[i].next)
     96             if(e[i].f&&!dep[e[i].to]){
     97                 dep[e[i].to]=dep[que[h]]+1;
     98                 if(e[i].to==T)return true;
     99                 que[++t]=e[i].to;
    100             }
    101     }
    102     return dep[T];
    103 }
    104 int dfs(int now,int flow){
    105     int i,ret=0;
    106     if(now==T)
    107         return flow;
    108     for(i=cut[now];i;i=e[i].next)
    109         if(e[i].f&&dep[e[i].to]==dep[now]+1){
    110             cut[now]=i;
    111             ret=dfs(e[i].to,min(flow,e[i].f));
    112             if(ret){
    113                 e[i].f-=ret;
    114                 e[e[i].cp].f+=ret;
    115                 return ret;
    116             }
    117         }
    118         else    cut[now]=i;
    119     return ret;
    120 }

    存在的问题:

    由于这个题是从学姐的summary里找到的;

    所以一开始就相信是二分题;

    如果对二分没有一定信仰的话,不知道还能不能做出来;

  • 相关阅读:
    Linux统计文件夹下所有文件的数量
    Linux查看文件最后几行的命令
    linux export将PATH环境变量误删了的解决办法
    laravel提示Mcrypt PHP extension required
    php(cli模式)执行文件传递参数
    shell判断文件是否存在,不存在则创建
    php获取Linux网卡信息
    使用iptraf,ifstat查看网络流量
    作用域
    头文件,库文件,重复包含
  • 原文地址:https://www.cnblogs.com/nietzsche-oier/p/8528534.html
Copyright © 2020-2023  润新知