對於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裏找到的;
因此一開始就相信是二分題;
若是對二分沒有必定信仰的話,不知道還能不能作出來;