日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[上下界网络流][二分] Bzoj P2406 矩阵

發布時間:2023/12/13 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [上下界网络流][二分] 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 }

?

轉載于:https://www.cnblogs.com/Comfortable/p/10304186.html

總結

以上是生活随笔為你收集整理的[上下界网络流][二分] Bzoj P2406 矩阵的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。