BZOJ1412
其實很容易想到割啦.然後再想一想就可以想到最小割啦.
割就是你選定一些邊,把這些邊去掉使得源點與匯點不連通.完全符合題目的意思呀.
又最小割等於最大流,跑一遍最大流就行啦
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 10500
#define inf 0x3f3f3f3f
using namespace std;
struct node{
int to,f,m;
node*rev,*next;
}*con[maxn];
int gox[5]={0,0,-1,1},goy[5]={1,-1,0,0};
void addedge(int x,int y,int mm)
{
node*p=new node;
p->to=y;p->f=0;p->m=mm;
p->next=con[x];con[x]=p;
p=new node;
p->to=x;p->f=p->m=0;
p->next=con[y];con[y]=p;
con[x]->rev=con[y];
con[y]->rev=con[x];
}
int n,m,a[110][110],s,t;
int dl[maxn*100],de[maxn],head,tail,v;
int poi(int x,int y)
{return (x-1)*m+y;}
bool pd(int x,int y)
{
if(x<1||x>n||y<1||y>m) return false;
return true;
}
bool bfs()
{
bool tmp=false;
head=tail=1;dl[tail]=s;
memset(de,-1,sizeof(de));
de[s]=1;
while(head<=tail)
{
v=dl[head++];
if(v==t) tmp=true;
for(node*p=con[v];p;p=p->next)
if(p->f<p->m&&de[p->to]==-1)
dl[++tail]=p->to,de[p->to]=de[v]+1;
}
return tmp;
}
int dinic(int v,int e)
{
int o=0,temp=0;
if(de[v]==-1) return 0;
if(v==t) return e;
for(node*p=con[v];p;p=p->next)
{
if(de[p->to]==de[v]+1&&p->f<p->m)
{
o=dinic(p->to,min(e-temp,p->m-p->f));
temp+=o;
p->f+=o;
p->rev->f-=o;
}
if(temp==e) break;
}
if(temp==0) de[v]=-1;
return temp;
}
int main()
{
scanf("%d%d",&n,&m);
s=0;t=n*m+1;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
if(a[i][j]==1) {
addedge(s,poi(i,j),inf);
for(int k=0;k<4;++k)
{
int xx=i+gox[k],yy=j+goy[k];
if(!pd(xx,yy)) continue;
if(a[xx][yy]!=1) addedge(poi(i,j),poi(xx,yy),1) ;
}
}
if(a[i][j]==0)
for(int k=0;k<4;++k)
{
int xx=i+gox[k],yy=j+goy[k];
if(!pd(xx,yy)) continue;
if(a[xx][yy]==2||a[xx][yy]==0) addedge(poi(i,j),poi(xx,yy),1);
}
if(a[i][j]==2)
addedge(poi(i,j),t,inf);
}
int ans=0;
while(bfs())
ans+=dinic(s,inf);
cout<<ans;
return 0;
}