bzoj 2406: 矩阵 (有上下界的网络流)
来源:互联网 发布:淘宝内部优惠券怎么弄 编辑:程序博客网 时间:2024/05/21 08:52
2406: 矩阵
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 229 Solved: 90
[Submit][Status][Discuss]
Description
Input
第一行两个数n、m,表示矩阵的大小。
接下来n行,每行m列,描述矩阵A。
最后一行两个数L,R。
Output
第一行,输出最小的答案;
Sample Input
2 2
0 1
2 1
0 1
0 1
2 1
0 1
Sample Output
1
HINT
对于100%的数据满足N,M<=200,0<=L<=R<=1000,0<=Aij<=1000
Source
HOME Back
题解:有上下界的网络流
直接二分要求的最小答案x,然后用有源汇有上下界的可行流判断。
s->i 容量[sumi[i]-x,sumi[i]+x] sumi[i]表示第i行的总和
j->t 容量[sumj[j]-x,sumj[j]+x] sumj[j]表示第j行的总和
i->j 容量[l,r]
然后按照有源汇有上下界的可行流建模即可。
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#define N 200000using namespace std;int in[N],out[N],point[N],v[N],remain[N],nxt[N];int deep[N],num[N],cur[N],ls,rs,n,m,tot;int a[203][203],sumi[N],sumj[N],last[N],ck[N];void add(int x,int y,int z){if (!z) return;tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z;tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;//cout<<x<<" "<<y<<" "<<z<<endl;}int addflow(int s,int t){int ans=1e9; int now=t;while (now!=s) {ans=min(ans,remain[last[now]]);now=v[last[now]^1];}now=t;while (now!=s){remain[last[now]]-=ans;remain[last[now]^1]+=ans;now=v[last[now]^1];}return ans;}void bfs(int s,int t){for (int i=1;i<=t;i++) deep[i]=t;deep[t]=0; queue<int> p; p.push(t);while (!p.empty()) {int now=p.front(); p.pop();for (int i=point[now];i!=-1;i=nxt[i]) if (deep[v[i]]==t&&remain[i^1]) deep[v[i]]=deep[now]+1,p.push(v[i]);}}void isap(int s,int t){bfs(s,t);int ans=0,now=s;for (int i=1;i<=t;i++) cur[i]=point[i];for (int i=1;i<=t;i++) num[deep[i]]++;while (deep[s]<t) {if (now==t) {ans+=addflow(s,t); now=s;}bool pd=false;for (int i=cur[now];i!=-1;i=nxt[i]) if (deep[v[i]]+1==deep[now]&&remain[i]) { pd=true; cur[now]=i; last[v[i]]=i; now=v[i]; break; }if (!pd) {int minn=t; for (int i=point[now];i!=-1;i=nxt[i]) if (remain[i]) minn=min(minn,deep[v[i]]); if (!--num[deep[now]]) break; num[deep[now]=minn+1]++; cur[now]=point[now]; if (now!=s) now=v[last[now]^1];}}}bool check(){for (int i=1;i<=n+m+2;i++) if (remain[ck[i]^1]) return false;return true;}bool solve(int x){tot=-1;memset(point,-1,sizeof(point));memset(num,0,sizeof(num));memset(in,0,sizeof(in));memset(out,0,sizeof(out));int s=1; int t=n+m+2;for (int i=1;i<=n;i++) {add(s,i+1,2*x);in[i+1]+=sumi[i]-x;out[s]+=sumi[i]-x;}for (int i=1;i<=m;i++) {add(i+n+1,t,2*x);in[t]+=sumj[i]-x;out[i+n+1]+=sumj[i]-x;}for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { add(i+1,j+n+1,rs-ls); in[j+n+1]+=ls; out[i+1]+=ls; }int ss=t+1; int tt=ss+1;for (int i=1;i<=t;i++){int k=out[i]-in[i];if (k>=0) add(i,tt,k);else add(ss,i,-k);ck[i]=tot;}add(t,s,1e9);isap(ss,tt);//for (int i=1;i<=n+m+1;i++) //cout<<remain[ck[i]^1]<<" ";//cout<<endl;if (check()) return true;return false;}int main(){freopen("a.in","r",stdin);scanf("%d%d",&n,&m);int sum=0;for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { scanf("%d",&a[i][j]); sum+=a[i][j]; sumi[i]+=a[i][j]; sumj[j]+=a[i][j]; }scanf("%d%d",&ls,&rs);int l=0; int r=sum; int ans;//cout<<ls<<" "<<rs<<endl;for (int i=1;i<=n;i++) r=min(r,sumi[i]);for (int i=1;i<=m;i++) r=min(r,sumj[i]);ans=r;//cout<<l<<" "<<r<<endl;while (l<=r) {int mid=(l+r)/2;if (solve(mid)) ans=min(ans,mid),r=mid-1;else l=mid+1; }printf("%d\n",ans);}
0 0
- bzoj 2406: 矩阵 (有上下界的网络流)
- [上下界网络流判定] BZOJ 2406 矩阵
- bzoj 2406: 矩阵 二分答案+上下界网络流
- 【bzoj 2502】清理雪道(有上下界的网络流)
- 有上下界的网络流
- 【有上下界的网络流】
- 有上下界限制的网络流
- 有上下界的网络流专辑
- 有上下界的网络流问题
- 有上下界的网络流
- 有上下界的网络流
- 有上下界的网络流问题
- 有上下界的网络流
- 有上下界的网络流
- 【有上下界的网络流】
- 【自用】有上下界的网络流
- 有上下界的网络流问题
- 有上下界的网络流
- oracle 按日期条件查询 to_date
- Android SeekBar拖动条
- 类型参数的约束(C# 编程指南)
- 代码初始化提交到svn, AndroidStudio关联SVN
- HDU 2586 How far away ?(map+lca【暴力水】)
- bzoj 2406: 矩阵 (有上下界的网络流)
- Linux下压缩、解压缩
- request.getInputStream()只能获取一次的问题
- Python2016阅读历史
- Android组件之ContentProvider(二)——共享单词本
- Kurento应用开发指南(以Kurento 5.0为模板) 之三:示例教程 一对多的视频呼叫
- 给UITableView的侧滑删除增加多个按钮
- 2017年1月27日
- 动态SQL