BZOJ 1412: [ZJOI2009]狼和羊的故事
Description
“狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。 Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。
Input
文件的第一行包含两个整数n和m。接下来n行每行m个整数,1表示该格子属于狼的领地,2表示属于羊的领地,0表示该格子不是任何一只动物的领地。
Output
文件中仅包含一个整数ans,代表篱笆的最短长度。
Sample Input
2 2
2 2
1 1
Sample Output
2
数据范围
10%的数据 n,m≤3
30%的数据 n,m≤20
100%的数据 n,m≤100
HINT
Source
Solution
问题实际转化成了两个点集的分割问题,即最小割。
先让S连向所有羊,T连向所有狼,容量都为inf。(保证不会被割掉)
再让所有狼连向四联通块,空地也是。跑最大流即可。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,x) for(int i=head[x];i;i=e[i].next)
#define mem(a,x) memset(a,x,sizeof(a))
typedef long long LL;
typedef double DB;
using namespace std;
template <typename T> inline T read(T &a) {
T x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') f=(ch=='-')?-1:f,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+(ch-'0'),ch=getchar();a=f*x;
}
const int inf=0x3f3f3f3f,T=1e4+1;
int head[10005],q[10005],h[10005],cur[10005];
int cnt=1,ans,n,m;
int xx[4]= {0,0,1,-1},yy[4]= {1,-1,0,0},mp[105][105];
struct data {int to,next,v;} e[500001];
void ins(int u,int v,int w) {e[++cnt]=(data){v,head[u],w},head[u]=cnt;}
void insert(int u,int v,int w) {ins(u,v,w),ins(v,u,0);}
bool bfs() {
int t=0,w=1,i,now;
memset(h,-1,sizeof(h));
q[0]=0,h[0]=0;
while(t<w) {
now=q[t++];
rep(i,now) if(e[i].v&&h[e[i].to]==-1) h[e[i].to]=h[now]+1,q[w++]=e[i].to;
}
return !(h[T]==-1);
}
int dfs(int x,int f) {
if(x==T) return f;
int w,used=0;
for(int &i=cur[x];i;i=e[i].next)
if(e[i].v&&h[e[i].to]==h[x]+1) {
w=f-used;
w=dfs(e[i].to,min(w,e[i].v));
e[i].v-=w,e[i^1].v+=w;
used+=w;
if(used==f) return f;
}
if(!used) h[x]=-1;
return used;
}
void dinic() {
while(bfs()) {
fo(i,0,T) cur[i]=head[i];
ans=ans+dfs(0,inf);
}
}
void build() {
fo(i,1,n) fo(j,1,m) {
if(mp[i][j]==1) insert(0,(i-1)*m+j,inf);
if(mp[i][j]==2) insert((i-1)*m+j,T,inf);
fo(k,0,3) {
int x=i+xx[k],y=j+yy[k];
if(x<1||x>n||y<1||y>m||mp[i][j]==2) continue;
if(mp[i][j]!=1||mp[x][y]!=1) insert((i-1)*m+j,(x-1)*m+y,1);
}
}
}
int main() {
freopen("1412.in","r",stdin);
read(n),read(m);
fo(i,1,n) fo(j,1,m) read(mp[i][j]);
build(),dinic();
printf("%d",ans);
return 0;
}