bzoj1412 狼和羊的故事 网络流

       实际上就是在狼和羊之间连边,求最小割。但是狼和羊的领地之间可能有空地,因此空地也要连。然后建立超级源点和超级汇点,跑最大流即可。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#define inf 1000000000
#define N 10005
#define M 100005
using namespace std;

int m,n,tot=1,gol,fst[N],pnt[M],len[M],nxt[M],d[N],h[N],a[105][105];
const int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
void add(int aa,int bb,int cc){
	pnt[++tot]=bb; len[tot]=cc; nxt[tot]=fst[aa]; fst[aa]=tot;
}
bool bfs(){
	int head=0,tail=1; h[1]=0;
	memset(d,-1,sizeof(d)); d[0]=0;
	while (head<tail){
		int x=h[++head],p;
		for (p=fst[x]; p; p=nxt[p]) if (len[p]){
			int y=pnt[p];
			if (d[y]==-1){ d[y]=d[x]+1; h[++tail]=y; }
		}
	}
	return d[gol]!=-1;
}
int dfs(int x,int rst){
	if (x==gol || !rst) return rst; int p,flow=0;
	for (p=fst[x]; p; p=nxt[p]) if (len[p]){
		int y=pnt[p]; if (d[x]+1!=d[y]) continue;
		int tmp=dfs(y,min(rst,len[p])); if (!tmp) continue;
		flow+=tmp; len[p]-=tmp;
		len[p^1]+=tmp; rst-=tmp; if (!rst) break; 
	}
	if (!flow) d[x]=-1; return flow;
}
int pt(int x,int y){ return (x-1)*n+y; }
int main(){
	scanf("%d%d",&m,&n); int i,j,k; gol=m*n+1;
	for (i=1; i<=m; i++)
		for (j=1; j<=n; j++) scanf("%d",&a[i][j]);
	for (i=1; i<=m; i++) for (j=1; j<=n; j++){
		if (a[i][j]==1){ add(0,pt(i,j),inf); add(pt(i,j),0,0); }
		else if (a[i][j]==2){ add(pt(i,j),gol,inf); add(gol,pt(i,j),0); continue; }
		for (k=0; k<4; k++){
			int x=i+dx[k],y=j+dy[k];
			if (x>0 && x<=m && y>0 && y<=n && (a[i][j]!=1 || a[x][y]!=1)){
				add(pt(i,j),pt(x,y),1); add(pt(x,y),pt(i,j),0);
			}
		}
	}
	int ans=0; while (bfs()) ans+=dfs(0,inf); printf("%d\n",ans);
	return 0;
}

by lych
2016.2.24

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值