bzoj 2406: 矩陣 ——solution

對於100%的數據知足N,M<=200,0<=L<=R<=1000,0<=Aij<=1000php

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



題中式的含義爲構造B矩陣ui

使得spa

B中每一個元素在LR之間.net

且矩陣(A-B)的每一行的和的絕對值與每一列的和的絕對值構成的數集code

最大值最小;blog

考慮枚舉這個數集的上界;get

這個能夠二分;string

當咱們二分到一個上界後,考慮如何check;it

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\n",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裏找到的;

因此一開始就相信是二分題;

若是對二分沒有必定信仰的話,不知道還能不能作出來;

相關文章
相關標籤/搜索