Description
“狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......”
Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干!
Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。
通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。
Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。
Input
输入数据存放在文本文件ws.in中。
文件的第一行包含两个整数n和m。接下来n行每行m个整数,1表示该格子属于狼的领地,2表示属于羊的领地,0表示该格子不是任何一只动物的领地。
Output
输出数据存放在文本文件ws.out中。
文件中仅包含一个整数ans,代表篱笆的最短长度。
Sample Input
2 2
2 2
1 1
Sample Output
2
Data Constraint
10%的数据 n,m≤3
30%的数据 n,m≤20
100%的数据 n,m≤100
题解
题目的要求就是通过加建围栏要把狼还有羊分开,
转化一下模型,就是最小割了。
每一个点与周围的点四路通,
就相当于连一条边,
如果建一个围栏,就等同于将这条边割掉。
将所有的羊与源点连一条边,
所有的狼和汇点连一条边,
点与点之间连一条边权为1的边。
最后跑最大流就行了。
code
#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 100003
#define M 103
#define db double
#define P putchar
#define G getchar
#define inf 998244353
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
int nxt[N*2],to[N*2],v[N*2],last[N],cur[N],tot;
int q[N],h[N],S,T,ans;
int a[M][M],n,m,t;
bool bfs()
{
int head=0,tail=1;
for(int i=0;i<=T;i++)h[i]=-1;
q[0]=S;h[S]=0;
while(head!=tail)
{
int now=q[head];head++;
for(int i=last[now];i;i=nxt[i])
if(v[i] && h[to[i]]==-1)
{
h[to[i]]=h[now]+1;
q[tail++]=to[i];
}
}
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=nxt[i])
if(h[to[i]]==h[x]+1)
{
w=f-used;
w=dfs(to[i],min(w,v[i]));
v[i]-=w;v[i^1]+=w;
if(v[i])cur[x]=i;
used+=w;
if(used==f)return f;
}
if(!used)h[x]=-1;
return used;
}
void dinic()
{
while(bfs())
{
for(int i=0;i<=T;i++)
cur[i]=last[i];
ans+=dfs(S,inf);
}
}
void ins(int x,int y,int z)
{
nxt[++tot]=last[x];
to[tot]=y;
v[tot]=z;
last[x]=tot;
}
int get(int x,int y)
{
return x*m-m+y;
}
int main()
{
tot=1;read(n);read(m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
read(a[i][j]);
S=n*m+1;T=S+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
t=get(i,j);
if(a[i][j]==1)ins(S,t,inf),ins(t,S,inf);
if(a[i][j]==2)ins(T,t,inf),ins(t,T,inf);
if(i!=n)ins(t,get(i+1,j),1),ins(get(i+1,j),t,1);
if(j!=m)ins(t,get(i,j+1),1),ins(get(i,j+1),t,1);
}
dinic();
printf("%d\n",ans);
}