您的位置:首页 > 理论基础 > 计算机网络

bzoj1001: [BeiJing2006]狼抓兔子(网络流模板题:最大流)

2018-02-28 08:35 411 查看
题目传送门
题目大意:
1 一个矩阵(原题的表述 n m 感觉数据都写错了),从左上走到右下,求流量和。
解题思路:
1 构图的连边有三种:横边/竖边/斜边,源点在左上角(1,1),汇点在右下角(n,m);
2 构图结束,直接跑网络流就行。
网络流思路:
1 网络流的模板思路主要三个地方:构反向边/用宽搜分层/用深搜推流量
2 网络流的题目一般都难在构图,但这题是模板,构图还是比较简单,目标是理解上面的三个思路
上代码了吧
1 这题有个细节要注意,每个点能向(右/下/右下)三个方向,连(双向)边,所以边的数组是点的6倍~
2 bz同学卡数据卡得很好~#include<cstdio>

const int mx=1000005,inf=999999999;

struct nodx{int h,d;}a[mx];
struct nodb{int x,y,c,f,gg;}b[mx*6];
int n,m,len=0,l[mx],tou,wei,st,ed;

void ins(int x,int y,int c)
{
len++;b[len].x=x;b[len].y=y;b[len].c=c;b[len].f=len+1;
b[len].gg=a[x].h;a[x].h=len;
len++;b[len].x=y;b[len].y=x;b[len].c=c;b[len].f=len-1;
b[len].gg=a[y].h;a[y].h=len;
}
bool bfs()
{
for(int i=1;i<=ed;i++) a[i].d=0;
tou=1;wei=2;l[1]=st;a[st].d=1;
while(tou<wei)
{
int x=l[tou];
for(int i=a[x].h;i>0;i=b[i].gg)
{
int y=b[i].y;
if(a[y].d==0 &&b[i].c>0)
{
a[y].d=a[x].d+1; l[wei++]=y;
}
}tou++;
}
if(a[ed].d>0) return 1; return 0;
}
int minn(int x,int y) { return x<y?x:y; }
int dfs(int x,int k)
{
if(x==ed) return k;
int t=0;
for(int i=a[x].h;i>0;i=b[i].gg)
{
int y=b[i].y;
if(a[y].d==a[x].d+1&&t<k&&b[i].c>0)
{
int dx=dfs(y,minn(b[i].c,k-t));
t+=dx; b[i].c-=dx; b[b[i].f].c+=dx;
}
}
if(t==0) a[x].d=0; return t;
}

int main()
{
scanf("%d %d",&n,&m);int c;
for(int i=1;i<=n*m;i++) a[i].h=0;
for(int i=1;i<=n;i++) //横边
{
for(int j=1;j<m;j++)
{
scanf("%d",&c);
ins((i-1)*m+j,(i-1)*m+j+1,c);
}
}
for(int i=1;i<n;i++)//竖边
{
for(int j=1;j<=m;j++)
{
scanf("%d",&c);
ins((i-1)*m+j,i*m+j,c);
}
}
for(int i=1;i<n;i++)//斜边
{
for(int j=1;j<m;j++)
{
scanf("%d",&c);
ins((i-1)*m+j,i*m+j+1,c);
}
}

st=1,ed=n*m;
int ans=0;
while(bfs())
{
ans+=dfs(st,inf);
}

printf("%d\n",ans);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络流