BZOJ 3698 XWW的难题
2017-04-27 23:26
316 查看
上下界最大流
好久没写上下界的网络流了,赶快复习一遍。对于这道题建图不难,就是把行、列当成点,一个连S,一个连T。一个格子当成行到列的边,上下取整当成上下界即可。
先说一下上下界可行流怎么搞。我们只要考虑把下界填平使得图流量平衡即可。对于入下界大于出下界的点,因为要填平下界,而出去的流量少了,因此要给它补充一些流量,S’向它连差值的边即可,反之连T’。
然后考虑上下界最大流怎么搞。一个办法是按照论文里说的二分出一个答案,T->S的连这个权值的边,然后判有没有可行流。正确性易证,但是复杂度带一个log。
一个更高效的算法是先找出原图的可行流,然后直接从S到T再跑最大流即可得到答案。因为可行流保证了在有下界情况下的流量平衡,因此暴力增广是对的。
最后每一条边的下界+流量就是这条边在原图的真实流量。
然后这题有点坑,矩阵里可以有负数,直接用int来取整是向0取整的!……因此要用floor和ceil,坑了半天好气啊……
好久没写上下界的网络流了,赶快复习一遍。对于这道题建图不难,就是把行、列当成点,一个连S,一个连T。一个格子当成行到列的边,上下取整当成上下界即可。
先说一下上下界可行流怎么搞。我们只要考虑把下界填平使得图流量平衡即可。对于入下界大于出下界的点,因为要填平下界,而出去的流量少了,因此要给它补充一些流量,S’向它连差值的边即可,反之连T’。
然后考虑上下界最大流怎么搞。一个办法是按照论文里说的二分出一个答案,T->S的连这个权值的边,然后判有没有可行流。正确性易证,但是复杂度带一个log。
一个更高效的算法是先找出原图的可行流,然后直接从S到T再跑最大流即可得到答案。因为可行流保证了在有下界情况下的流量平衡,因此暴力增广是对的。
最后每一条边的下界+流量就是这条边在原图的真实流量。
然后这题有点坑,矩阵里可以有负数,直接用int来取整是向0取整的!……因此要用floor和ceil,坑了半天好气啊……
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define N 222 using namespace std; namespace runzhe2000 { typedef double db; const int INF = 1<<29; int S, T, SS, TT, s, t, q , level ; int ecnt = 1, n, nn, last , cur , deg , val ; db a ; struct edge{int next, to, flow;}e[N*N<<2]; void addedge(int a, int b, int down, int up) { // printf("%d %d %d %d\n",a,b,down,up); // printf("%d %d %d\n",a,b,up-down); deg[a] -= down; deg[b] += down; e[++ecnt] = (edge){last[a], b, up-down}; last[a] = ecnt; e[++ecnt] = (edge){last[b], a, 0}; last[b] = ecnt; } int bfs() { memset(level,0,sizeof(level)); level[q[0] = s] = 1; for(int head=0, tail=1; head<tail; head++) { int x = q[head]; for(int i = last[x]; i; i = e[i].next) { int y = e[i].to; if(!level[y] && e[i].flow) { level[y] = level[x] + 1, q[tail++] = y; if(y == t) return 1; } } } return 0; } int dfs(int x, int flow) { if(x == t) return flow; int use = 0; for(int &i = cur[x]; i; i = e[i].next) { int y = e[i].to; if(level[x]+1 != level[y]) continue; int w = dfs(y, min(flow-use, e[i].flow)); e[i].flow -= w; e[i^1].flow += w; use += w; if(use == flow) return use; } return use; } int dinic(){int r = 0; for(; bfs(); memcpy(cur, last, sizeof(cur)), r += dfs(s, INF)); return r;} void main() { scanf("%d",&n); S = n+n+1, T = n+n+2, SS = n+n+3, TT = n+n+4; nn = n+n+4; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) scanf("%lf",&a[i][j]); for(int i = 1; i < n; i++) for(int j = 1; j < n; j++) addedge(i, j+n, (int)floor(a[i][j]), (int)ceil(a[i][j])); for(int i = 1; i < n; i++) addedge(S, i, (int)floor(a[i] ), (int)ceil(a[i] )), addedge(i+n, T, (int)floor(a [i]), (int)ceil(a [i])); for(int i = 1; i <= nn; i++) deg[i] > 0 ? addedge(SS, i, 0, deg[i]) : addedge(i, TT, 0, -deg[i]); int v = 0; for(int i = last[SS]; i; i = e[i].next) v += e[i].flow; addedge(T, S, 0, INF); s = SS, t = TT; if(dinic() != v) return (void)puts("No"); for(int i = last[S]; i; i = e[i].next) if(e[i].to == T) e[i].flow = e[i^1].flow = 0;// int ans = 0; s = S, t = T; dinic(); for(int i = 1; i < n; i++) for(int j = last[i]; j; j = e[j].next) if(n < e[j].to && e[j].to <= n+n) ans += (int)floor(a[i][e[j].to-n]) + e[j^1].flow, val[i][e[j].to - n] = e[j^1].flow; printf("%d\n",ans*3); } } int main() { runzhe2000::main(); }
相关文章推荐
- [上下界网络流 二分] BZOJ 3698 XWW的难题
- [BZOJ3698]XWW的难题解题报告|上下界网络流|有源汇最大流
- [BZOJ3698]XWW的难题(有源汇有上下界的最大流)
- 【BZOJ3698】XWW的难题 有上下界的最大流
- [BZOJ3698] XWW的难题 网络流
- 【bzoj3698】【XWW的难题】【有上下界的网络流】
- 【bzoj3698】XWW的难题 有上下界的网络流
- bzoj 3698: XWW的难题 (有源汇有上下界的最大流)
- bzoj 3698 XWW的难题(有源汇的上下界最大流)
- [bzoj3698]XWW的难题 有源汇的上下界最大流
- BZOJ 3698(XWW的难题-上下界网络流+经典建模)
- XWW的难题(bzoj 3698)
- BZOJ 3698: XWW的难题 [有源汇上下界最大流]
- BZOJ 3698: XWW的难题|有上下界的网络流之最大流
- bzoj3698 XWW的难题(有源汇有上下界最大流)
- 【bzoj3698】XWW的难题 有源汇上下界网络流最大流
- [BZOJ3698]XWW的难题(有源汇上下界最大流+讲解)
- bzoj3698: XWW的难题 //有上下界有源汇最大流
- bzoj3698 XWW的难题
- 【bzoj3698】XWW的难题 有上下界最大流