题目描述:
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
题解:
(ps:好久没写blog了。。。
这题显然用网络流来解决。
最小割=最大流
用最少的栏杆将羊和狼隔开,可以转化成最小割的模型。
建立超级源S和超级汇T。将超级源与狼建边,流量为inf。将羊与超级汇建边,流量为inf。将狼与羊,空地与空地,空地与羊,狼与空地建边,流量为1。那么刷一次最小割(即刷DINIC)就是答案了。因为这样刷相当于找建围栏的最好方法。。。
代码如下:
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
const int maxm=105,maxn=500005,inf=1<<30,flg[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
int n,n1,m1,S,T,tot,ans,map[maxm][maxm],lnk[maxn],nxt[maxn],son[maxn],dep[maxn],w[maxn],que[maxn],cur[maxn];
inline int read(){
int x=0; char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x;
}
bool bfs(){
int head=0,tail=1; que[tail]=S;
memset(dep,255,sizeof(dep)); dep[S]=0;
while (head<tail) {
head++;
for (int j=lnk[que[head]];j!=-1;j=nxt[j])
if (dep[son[j]]==-1&&w[j]>0) {
dep[son[j]]=dep[que[head]]+1; que[++tail]=son[j];
}
}
if (dep[T]==-1) return 0; else return 1;
}
int dfs(int x,int flow) {
if (x==T) return flow;
for (int& j=cur[x];j!=-1;j=nxt[j])
if (dep[son[j]]==dep[x]+1&&w[j]!=0){
int x=dfs(son[j],min(flow,w[j]));
if (x) {w[j]-=x; w[j^1]+=x; return x;}
}
return 0;
}
int dinic(){
int sum; ans=0;
while (bfs()) {
for (int i=1;i<=T;i++) cur[i]=lnk[i];
while (sum=dfs(S,inf)) ans+=sum;
}
return ans;
}
void add(int x,int y,int z) {
son[++tot]=y,w[tot]=z,nxt[tot]=lnk[x],lnk[x]=tot;
son[++tot]=x,w[tot]=0,nxt[tot]=lnk[y],lnk[y]=tot;
}
int main(){
n1=read(),m1=read(); n=n1*m1; S=++n,T=++n; tot=-1;
memset(lnk,255,sizeof(lnk));
memset(nxt,255,sizeof(nxt));
for (int i=1;i<=n1;i++)
for (int j=1;j<=m1;j++){
map[i][j]=read();
if (map[i][j]==1) add(S,(i-1)*m1+j,inf);
else if (map[i][j]==2) add((i-1)*m1+j,T,inf);
}
for (int i=1;i<=n1;i++)
for (int j=1;j<=m1;j++)
for (int k=0;k<4;k++) {
int x=i+flg[k][0],y=j+flg[k][1];
if (x<1||x>n1||y<1||y>m1||map[i][j]==2) continue;
if (map[i][j]==1&&map[x][y]==1) continue;
add((i-1)*m1+j,(x-1)*m1+y,1);
}
printf("%d\n",dinic());
return 0;
}