您的位置:首页 > 其它

BZOJ 3698 XWW的难题

2017-04-27 23:26 316 查看
上下界最大流

好久没写上下界的网络流了,赶快复习一遍。对于这道题建图不难,就是把行、列当成点,一个连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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: