bzoj 2406 二分+有源有汇上下界网络流可行流判定

弱爆了,典型的行列建模方式,居然想不到,题做少了,总结少了。。。。。。

二分答案mid

s----------------------->i行----------------------->j列----------------------------->t

[si-mid,si+mid]                  [L,R]                 [s[j]-mid,s[j]+mid]

即对每一行建一个点,每一列建一个点,用边来表示某一行某一列上的东西.

这种建模方式一般要整体考虑行或列的某些信息.

  1  /**************************************************************
  2     Problem: 2406
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:396 ms
  7     Memory:4576 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11 #include <cstring>
 12 #define min(a,b) ((a)<(b)?(a):(b))
 13 #define oo 0x3f3f3f3f
 14 #define N 510
 15 #define S 100010
 16
 17 struct Dinic {
 18     int n, src, dst;
 19     int head[N], dest[S], flow[S], next[S], etot;
 20     int dep[N], cur[N], qu[N], bg, ed;
 21
 22     void init( int n, int src, int dst ) {
 23         memset( head, -1, sizeof(head) );
 24         etot = 0;
 25         this->n = n;
 26         this->src = src;
 27         this->dst = dst;
 28     }
 29     void adde( int u, int v, int f ) {
 30 //      fprintf( stderr, "Dinic::adde( %d %d %d )\n", u, v, f );
 31         next[etot]=head[u]; flow[etot]=f; dest[etot]=v; head[u]=etot++;
 32         next[etot]=head[v]; flow[etot]=0; dest[etot]=u; head[v]=etot++;
 33     }
 34     bool bfs() {
 35         memset( dep, 0, sizeof(dep) );
 36         qu[bg=ed=1] = src;
 37         dep[src] = 1;
 38         while( bg<=ed ) {
 39             int u=qu[bg++];
 40             for( int t=head[u]; ~t; t=next[t] ) {
 41                 int v=dest[t], f=flow[t];
 42                 if( f && !dep[v] ) {
 43                     dep[v] = dep[u]+1;
 44                     qu[++ed] = v;
 45                 }
 46             }
 47         }
 48         return dep[dst];
 49     }
 50     int dfs( int u, int a ) {
 51         if( u==dst || a==0 ) return a;
 52         int remain=a, past=0, na;
 53         for( int &t=cur[u]; ~t; t=next[t] ) {
 54             int v=dest[t], &f=flow[t], &vf=flow[t^1];
 55             if( f && dep[v]==dep[u]+1 && (na=dfs(v,min(remain,f))) ) {
 56                 f -= na;
 57                 vf += na;
 58                 remain -= na;
 59                 past += na;
 60                 if( !remain ) break;
 61             }
 62         }
 63         return past;
 64     }
 65     int maxflow() {
 66         int f = 0;
 67         while( bfs() ) {
 68             for( int u=1; u<=n; u++ ) cur[u]=head[u];
 69             f += dfs( src, oo );
 70         }
 71 //      fprintf( stderr, "maxflow() = %d\n", f );
 72         return f;
 73     }
 74 };
 75 struct TopBot {
 76     int n;
 77     int head[N], dest[S], top[S], bot[S], next[S], etot;
 78     int sin[N], sout[N];
 79     Dinic D;
 80     void init( int n ) {
 81         this->n = n;
 82         etot = 0;
 83         memset( head, 0, sizeof(head) );
 84         memset( sin, 0, sizeof(sin) );
 85         memset( sout, 0, sizeof(sout) );
 86     }
 87     void adde( int u, int v, int t, int b ) {
 88 //      fprintf( stderr, "TopBot::adde( %d %d [%d,%d] )\n", u, v, b, t );
 89         etot++;
 90         dest[etot] = v;
 91         top[etot] = t;
 92         bot[etot] = b;
 93         next[etot] = head[u];
 94         head[u] = etot;
 95         sin[v] += b;
 96         sout[u] += b;
 97     }
 98     bool ok() {
 99         int src=n+1, dst=n+2;
100         D.init( n+2, src, dst );
101         for( int u=1; u<=n; u++ )
102             for( int t=head[u]; t; t=next[t] ) {
103                 int v=dest[t];
104                 D.adde( u, v, top[t]-bot[t] );
105             }
106         int sumf = 0;
107         for( int u=1; u<=n; u++ ) {
108             if( sin[u]>sout[u] )
109                 D.adde( src, u, sin[u]-sout[u] );
110             else if( sin[u]<sout[u] ) {
111                 D.adde( u, dst, sout[u]-sin[u] );
112                 sumf += sout[u]-sin[u];
113             }
114         }
115 //      fprintf( stderr, "sumf=%d\n", sumf );
116         return D.maxflow()==sumf;
117     }
118 }T;
119
120 int n, m;
121 int w[N][N], L, R;
122 int s[2][N];
123
124 bool ok( int mid ) {
125     int src = n+m+1, dst = n+m+2;
126     int st=0, sb=0;
127     T.init(dst);
128     for( int i=1; i<=n; i++ ) {
129         int t=s[0][i]+mid, b=s[0][i]-mid;
130         b = b<0 ? 0 : b;
131         T.adde( src, i, t, b );
132         st += t;
133         sb += b;
134     }
135     for( int i=1; i<=n; i++ )
136         for( int j=1; j<=m; j++ )
137             T.adde( i, n+j, R, L );
138     for( int i=1; i<=m; i++ ) {
139         int t=s[1][i]+mid, b=s[1][i]-mid;
140         b = b<0 ? 0 : b;
141         T.adde( n+i, dst, t, b );
142     }
143     T.adde( dst, src, st, sb );
144     return T.ok();
145 }
146 int main() {
147     scanf( "%d%d", &n, &m );
148     for( int i=1; i<=n; i++ )
149         for( int j=1; j<=m; j++ ) {
150             scanf( "%d", &w[i][j] );
151             s[0][i] += w[i][j];
152             s[1][j] += w[i][j];
153         }
154     scanf( "%d%d", &L, &R );
155     int lf=0, rg=200000;
156     while( lf<rg ) {
157         int mid=lf+((rg-lf)>>1);
158         if( ok(mid) ) rg=mid;
159         else lf=mid+1;
160     }
161     printf( "%d\n", lf );
162 }

时间: 2024-08-08 21:57:29

bzoj 2406 二分+有源有汇上下界网络流可行流判定的相关文章

sgu 194 上下界网络流可行流判定+输出可行流

1 #include <cstdio> 2 #include <cstring> 3 #define min(a,b) ((a)<(b)?(a):(b)) 4 #define oo 0x3f3f3f3f 5 #define N 210 6 #define M 100010 7 8 struct Dinic { 9 int n, src, dst; 10 int head[N], dest[M], flow[M], eid[M], next[M], etot; 11 int c

POJ 2396 Budget (有源汇有上下界的可行流)

POJ 2396 Budget 链接:http://poj.org/problem?id=2396 题意:给定一个M*N的矩阵,给定每行每列的和,以及其中一些值的限定条件,问能否构成一个可行的矩阵. 思路: 添加一个源点,向每行连边,每条边的上下界都为该行的和:添加一个汇点,每列向汇点连边,边的上下界都为该列的和.然后每行向每列连边,边的上下界一开始为(0,INF),之后通过一些限定条件更新. 现在问题成了求一个有源汇有上下界的可行流.只需要再添加一个超级源点,一个超级汇点,并且将原图的汇点向源

[ACdream 1211 Reactor Cooling]无源无汇有上下界的可行流

题意:无源无汇有上下界的可行流 模型 思路:首先将所有边的容量设为上界减去下界,然后对一个点i,设i的所有入边的下界和为to[i],所有出边的下界和为from[i],令它们的差为dif[i]=to[i]-from[i],根据流量平衡原理,让出边和入边的下界相抵消,如果dif[i]>0,说明入边把出边的下界抵消了,还剩下dif[i]的流量必须要流过来(否则不满足入边的下界条件),这时从源点向i连一条容量为dif[i]的边来表示即可,如果dif[i]<0,同理应该从i向汇点连一条容量为-dif[i

ZOJ 2314 带上下界的可行流

对于无源汇问题,方法有两种. 1 从边的角度来处理. 新建超级源汇, 对于每一条有下界的边,x->y, 建立有向边 超级源->y ,容量为x->y下界,建立有向边 x-> 超级汇,容量为x->y下界.建立有向边 x->y,容量为x->y的上界减下界. 2 从点的角度来处理. 新建超级源汇,对于每个点流进的下界和为 in, 流出此点的下界和为out.如果in > out. 建立有向边 超级源->i,容量为in-out.反之,建立有向边 i->超级汇

【BZOJ2406】矩阵 二分+有上下界的可行流

[BZOJ2406]矩阵 Description Input 第一行两个数n.m,表示矩阵的大小. 接下来n行,每行m列,描述矩阵A. 最后一行两个数L,R. Output 第一行,输出最小的答案: Sample Input 2 2 0 1 2 1 0 1 Sample Output 1 HINT 对于100%的数据满足N,M<=200,0<=L<=R<=1000,0<=Aij<=1000 题解:容易想到二分,并且这个和式可以拆成$\sum A_{ij}-\sum B_

hdu 4940 Destroy Transportation system( 无源汇上下界网络流的可行流推断 )

题意:有n个点和m条有向边构成的网络.每条边有两个花费: d:毁坏这条边的花费 b:重建一条双向边的花费 寻找这样两个点集,使得点集s到点集t满足 毁坏全部S到T的路径的费用和 > 毁坏全部T到S的路径的费用和 + 重建这些T到S的双向路径的费用和. 思路1: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center&quo

ZOJ 3229 Shoot the Bullet 有源有汇带下界的最大流

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3229 Shoot the Bullet Time Limit: 2 Seconds      Memory Limit: 32768 KB      Special Judge Gensokyo is a world which exists quietly beside ours, separated by a mystical border. It is a u

hdu 4940 Destroy Transportation system( 无源汇上下界网络流的可行流判断 )

题意:有n个点和m条有向边构成的网络,每条边有两个花费: d:毁坏这条边的花费 b:重建一条双向边的花费 寻找这样两个点集,使得点集s到点集t满足 毁坏所有S到T的路径的费用和 > 毁坏所有T到S的路径的费用和 + 重建这些T到S的双向路径的费用和. 思路1: 然后这个无源汇带上下界网络流的可行流问题的求解方法见这里~~ 建图就是上面说的那样啦~最后判断有没有可行流就是求一下我们所构造的这个新的网络的最大流~然后判断一下这个最大流是否满流~(即判断最大流是否和附加源点的流出总量相等~~) cod

ZOJ 2314 Reactor Cooling(无源汇上下界网络流)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2314 题意: 给出每条边流量的上下界,问是否存在可行流,如果存在则输出. 思路:先定义D(u)为顶点u发出的所有弧的流量下界与进入顶点u的所有弧的流量下界和之差(out[u]-in[u]). 对于无源汇的网络流来说: (1)新增两个顶点S(附加源点)和T(附加汇点). (2)对原网络中每个顶点u,计算出D(u),如果D(u)>0,则增加一条新弧<u,T>,这条弧的