[洛谷P4001][BJOI2006]狼抓兔子

题目大意:给你一个n*m的网格图,有三种边,横的,纵的和斜的,要你求出它的最小割

题解:网络流

卡点:1.无向图,反向弧容量应和正向弧相同

C++ Code:

#include<cstdio>
#include<cstring>
#include<cctype>
#define maxn 1010*1010
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,a,u,v;
int d[maxn];
int q[maxn],h,t;
int start=1,end;
int head[maxn],cnt=2;
struct Edge{
	int to,nxt,cost;
}e[maxn*6];
char ch;
void read(int &x){
	ch=getchar();
	while (!isdigit(ch))ch=getchar();
	for (x=ch^48,ch=getchar();isdigit(ch);ch=getchar())x=x*10+(ch^48);
}
inline int min(int a,int b){return a<b?a:b;}
void add(int a,int b,int c){
	e[cnt]=(Edge){b,head[a],c};head[a]=cnt;
	e[cnt^1]=(Edge){a,head[b],c};head[b]=cnt^1;
	cnt+=2;
}
bool bfs(){
	memset(d,0,sizeof d);
	d[q[h=t=1]=start]=1;
	while (h<=t){
		int x=q[h++];
		if (x==end)return true;
		for (int i=head[x];i;i=e[i].nxt){
			int to=e[i].to;
			if ((!d[to])&&e[i].cost){
				d[to]=d[x]+1;
				q[++t]=to;
			}
		}
	}
	return d[end];
}
int dfs(int x,int low){
	if (x==end||!low)return low;
	int res=0,w;
	for (int i=head[x];i;i=e[i].nxt){
		int to=e[i].to;
		if ((d[to]==d[x]+1)&&e[i].cost){
			w=dfs(to,min(low-res,e[i].cost));
			e[i].cost-=w;
			e[i^1].cost+=w;
			res+=w;
			if (res==low)return res;
		}
	}
	if (!res)d[x]=-1;
	return res;
}
void dinic(){
	int ans=0,k;
	while (bfs()){
		k=dfs(start,inf);
		if (k>0)ans+=k;
	}
	printf("%d
",ans);
}
int main(){
	read(n),read(m);
	for (int i=1;i<=n;i++){
		for (int j=1;j<m;j++){
			read(a);
			u=(i-1)*m+j,v=u+1;
			add(u,v,a);
		} 
	}
	for (int i=1;i<n;i++){
		for (int j=1;j<=m;j++){
			read(a);
			u=(i-1)*m+j,v=u+m;
			add(u,v,a);
		} 
	}
	for (int i=1;i<n;i++){
		for (int j=1;j<m;j++){
			read(a);
			u=(i-1)*m+j,v=u+m+1;
			add(u,v,a);
		}
	}
	end=n*m;
	dinic();
	return 0;
}

  

原文地址:https://www.cnblogs.com/Memory-of-winter/p/9110501.html