ZJOI2009狼和羊的故事--dinic网络流

题意就是任意两个1和2都不能有路径相连通。

做法是最小割,但是暴力增广会T4个点,而dinic没记cur数组会T2个点,开了以后速度飞快。。。。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=105,Maxn=maxn*maxn,inf=1e9,dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
int a[maxn][maxn],dep[Maxn],cur[Maxn];
int Begin[Maxn],Next[Maxn*10],to[Maxn*10],p[Maxn*10],e=1;
void add(int u,int v,int flow){
	to[++e]=v,Next[e]=Begin[u],Begin[u]=e,p[e]=flow;
	to[++e]=u,Next[e]=Begin[v],Begin[v]=e,p[e]=0;
}
queue<int>q;
bool bfs(int s,int t){
	memset(dep,0,sizeof(dep));
	while(!q.empty())q.pop();
	dep[s]=1,q.push(s);
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=Begin[u];i;i=Next[i])
			if((!dep[to[i]])&&(p[i]))
				dep[to[i]]=dep[u]+1,q.push(to[i]);
	}
	return (dep[t]>0);
}
int dfs(int u,int t,int Maxflow){
	if(u==t)return Maxflow;
	int tmp;
	for(int &i=cur[u];i;i=Next[i])
		if((dep[to[i]]==dep[u]+1)&&(p[i]))
			if(tmp=dfs(to[i],t,min(Maxflow,p[i]))){
				p[i]-=tmp,p[i^1]+=tmp;
				return tmp;
			}
	return 0;
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			scanf("%d",&a[i][j]);
			if(a[i][j]==1)
				add(0,(i-1)*m+j,inf);
			else if(a[i][j]==2)
				add((i-1)*m+j,n*m+1,inf);
		}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(a[i][j]!=2)
				for(int k=0;k<4;k++){
					int x=i+dir[k][0],y=j+dir[k][1];
					if((x>0)&&(y>0)&&(x<=n)&&(y<=m)&&(a[x][y]!=1))
						add((i-1)*m+j,(x-1)*m+y,1);	
				}
	int ans=0,res;
	while(bfs(0,n*m+1)){
		for(int i=0;i<=n*m+1;i++)cur[i]=Begin[i];
		while(res=dfs(0,n*m+1,inf))ans+=res;
	}
	printf("%d\n",ans);
	return 0;
}

呵呵,很有意思吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值