題目:http://www.lydsy.com/JudgeOnline/problem.php?id=1412
思路:最大流求最小割,每個點向四周的點連容量至少為4的邊,然后對于每個1的點把兔,從源點向該點連容量1的邊停巷,對于每個2的點,從改點向匯點連容量為1的邊低飒,跑一次最大流即可仁期。
代碼:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 101
#define MAXV 10010
struct node {
node *next,*pair;
int t,f;
};
node *head[MAXV],*d[MAXV];
int gap[MAXV],h[MAXV];
int n,m;
int a[MAXN][MAXN],N[MAXN][MAXN];
int v=0;
int S,T;
void INSERT(int s,int t,int f){
node *p=new(node);
p->t=t;
p->f=f;
p->next=head[s];
head[s]=p;
p=new(node);
p->t=s;
p->f=0;
p->next=head[t];
head[t]=p;
head[s]->pair=head[t];
head[t]->pair=head[s];
}
int sap(int v,int flow){
if (v==T){
return flow;
}
int rec=0;
for (node *p=d[v];p;p=p->next){
if (p->f&&h[v]==h[p->t]+1){
int ret=sap(p->t,min(flow-rec,p->f));
p->f-=ret;
p->pair->f+=ret;
d[v]=p;
if ((rec+=ret)==flow){
return flow;
}
}
}
if (!(--gap[h[v]])){
h[S]=T;
}
gap[++h[v]]++;
d[v]=head[v];
return rec;
}
int main(){
memset(head,0,sizeof(head));
memset(gap,0,sizeof(gap));
memset(h,0,sizeof(h));
scanf("%d%d",&n,&m);
for (int i=0;i++<n;){
for (int j=0;j++<m;){
N[i][j]=++v;
scanf("%d",&a[i][j]);
}
}
S=++v;
T=++v;
for (int i=0;i++<n;){
for (int j=0;j++<m;){
if (i-1){
INSERT(N[i][j],N[i-1][j],1);
}
if (j-1){
INSERT(N[i][j],N[i][j-1],1);
}
if (i+1<=n){
INSERT(N[i][j],N[i+1][j],1);
}
if (j+1<=m){
INSERT(N[i][j],N[i][j+1],1);
}
switch (a[i][j]){
case 1:
INSERT(S,N[i][j],0x7fffffff);
break;
case 2:
INSERT(N[i][j],T,0x7fffffff);
break;
}
}
}
gap[0]=T;
for (int i=0;i++<T;){
d[i]=head[i];
}
int mincut=0;
while (h[S]<T){
mincut+=sap(S,0x7fffffff);
}
printf("%d\n",mincut);
return 0;
}