原题: http://acm.hdu.edu.cn/showproblem.php?pid=3046
题意:
n*m网格,有些块有1(羊),有些有2(狼),问最少多少块1长度的板子,隔开所有的1和2(任意一个1不能达到任意一个2)
解析:
将边界视为两个块之间的一条边,就变成了网络流问题。现在求的最小割,使到达汇点的流量为0,根据定理,最小割最大流,直接求最大流即可
每两个格子之间连1,源点到羊inf,狼到汇点inf
#include
#include
#include
#include
#include
#include
using namespace std;
const int inf=0x3f3f3f3f;
const int N=40500,M=405000;
int head[N],nex[M],to[M],val[M],now;
void add(int a,int b,int v){
to[++now]=b;val[now]=v;nex[now]=head[a];head[a]=now;
to[++now]=a;val[now]=0;nex[now]=head[b];head[b]=now;
}
//*********************
int sp,ep,d[N];
int bfs(){
queue<int>Q;
memset(d,-1,sizeof(d));
d[sp]=0;
Q.push(sp);
while(!Q.empty()){
int p=Q.front();Q.pop();
for(int i=head[p];~i;i=nex[i]){
int u=to[i];
if(d[u]==-1&&val[i]>0){
d[u]=d[p]+1;
Q.push(u);
}
}
}
return d[ep]!=-1;
}
int dfs(int p,int v){
int r=0;
if(p==ep)return v;
for(int i=head[p];(~i)&&r<v;i=nex[i]){
int u=to[i];
if(val[i]>0&&d[u]==d[p]+1){
int x=dfs(u,min(val[i],v-r));
r+=x;
val[i]-=x;
val[i^1]+=x;
}
}
if(!r)d[p]=-2;
return r;
}
int dinic(){
int ans=0,t;
while(bfs()){
while(t=dfs(sp,inf))ans+=t;
}
return ans;
}
//***********************
void init(){
now=-1;//要求第一条边为0
memset(head,-1,sizeof(head));
}
int n,m;
int Mp[201][201];
int id(int i,int j){return (i-1)*201+j;}
int di[4][2]={{0,1},{1,0},{-1,0},{0,-1}};
int main(){int ca=0;while(cin>>n>>m){
init();
sp=0;ep=40400;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&Mp[i][j]);
for(int k=0;k<4;k++){
int x=i+di[k][0],y=j+di[k][1];
if(x<1||y<1||x>n||y>m)continue;
add(id(i,j),id(x,y),1);
}
if(Mp[i][j]==1){
add(id(i,j),40400,inf);
}
if(Mp[i][j]==2){
add(0,id(i,j),inf);
}
}
}
int ans=dinic();
printf("Case %d:\n%d\n",++ca,ans);
}}