BZOJ1001: [BeiJing2006]狼抓兔子(网络流)

容易发现答案就是最小割

由最小割最大流定理知答案就是原图的最大流

直接上dinic就行了

 

建图时要注意边是无向的,反向边流量不为0

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6+5,maxe=6e6+5;
int n,m,s,t,ans,tot=1,idx[1005][1005],son[maxe],cur[maxn],w[maxe],nxt[maxe],lnk[maxn],d[maxn],que[maxn];
inline int read(){
	int ret=0,fh=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')fh=-fh;ch=getchar();}
	while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
	return ret*fh;
}
bool BFS(){
	memset(d,-1,sizeof(d));
	d[s]=1,que[1]=s;
	int hd=0,tl=1;
	while(hd<tl){
		int x=que[++hd];
		for(int j=lnk[x];j;j=nxt[j]){
			int v=son[j];
			if(w[j]&&d[v]==-1){
				d[v]=d[x]+1;
				que[++tl]=v;
			}
		}
	}
	return d[t]!=-1;
}
int DFS(int x,int f){
	if(x==t) return f;
	int f0=0;
	for(int&j=cur[x];j;j=nxt[j]){
		int v=son[j];
		if(w[j]&&d[v]==d[x]+1){
			int k=DFS(v,min(f,w[j]));
			if(k>0){
				w[j]-=k,w[j^1]+=k;
				f-=k,f0+=k;
				if(!f) break;
			}	
		}
	}
	return f0;
}
void add_e(int x,int y,int z){son[++tot]=y,w[tot]=z,nxt[tot]=lnk[x],lnk[x]=tot;}
int main(){
	freopen("P1001.in","r",stdin);
	freopen("P1001.out","w",stdout);
	n=read(),m=read();
	int cnt=0;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++){
		idx[i][j]=++cnt;
	}
	s=idx[1][1],t=idx[n][m];
	for(int i=1;i<=n;i++)
	for(int j=1;j<m;j++){
		int x=read();
		add_e(idx[i][j],idx[i][j+1],x);
		add_e(idx[i][j+1],idx[i][j],x);
	}
	for(int i=1;i<n;i++)
	for(int j=1;j<=m;j++){
		int x=read();
		add_e(idx[i][j],idx[i+1][j],x);
		add_e(idx[i+1][j],idx[i][j],x);
	}
	for(int i=1;i<n;i++)
	for(int j=1;j<m;j++){
		int x=read();
		add_e(idx[i][j],idx[i+1][j+1],x);
		add_e(idx[i+1][j+1],idx[i][j],x);
	}
	while(BFS()){
		memcpy(cur,lnk,sizeof(cur));
		ans+=DFS(s,2e9);
	}
	printf("%d\n",ans);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值