[ZJOI2009] 狼和羊的故事
题目大意
给定一个 \(nm\) 的由 \((0,1,2)\) 组成的矩阵,要求在两个数之间建墙,使得任意两个 \(1\) 和 \(2\) 不连通(两个数相邻且之间无墙即为联通),求最少要建多少墙。
这道题可视作是要将 \(1\) 和 \(2\) 划分成两个集合,考虑最小割。
\(s\longrightarrow\{(i,j)|mp_{i,j}==1\}\),容量 \(+\infty\)。
\(t\longrightarrow\{(i,j)|mp_{i,j}==2\}\),容量 \(+\infty\)。
容量 \(+\infty\) 是为了保证最终不会出现 \(1\) 和 \(2\) 在一个集合内的情况。
由于每个格子和上下左右四个格子相邻,所以将它和周围的格子连起来。
\((i,j)\longrightarrow(i+1,j)\),容量为 \(1\)。
\((i,j)\longrightarrow(i,j+1)\),容量为 \(1\)。
\((i,j)\longrightarrow(i-1,j)\),容量为 \(1\)。
\((i,j)\longrightarrow(i,j-1)\),容量为 \(1\)。
这样,跑最小割时,每割掉一条边,就相当于在这两个格子之间建一堵墙,代价 \(++\) ,所以上面建图时容量为 \(1\) 。
最终最小割即为答案。
Code
#include<bits/stdc++.h>
//#define int long long
#define pair pair<int,int>
using namespace std;
inline void end()
{
puts("");
system("pause");
}
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
const int N=1e4+4,M=5e5+5;
int n,m,s,t,ans;
int first[N],nex[M],to[M],w[M],num=1;
inline void add(int u,int v,int val)
{
nex[++num]=first[u];
first[u]=num;
to[num]=v;
w[num]=val;
}
inline void Add(int u,int v,int val)
{
add(u,v,val);
add(v,u,0);
}
namespace ISAP
{
int dep[N],gap[N],cur[N];
void bfs()
{
memset(dep,-1,sizeof(dep));
memset(gap,0,sizeof(gap));
queue<int> q;
q.push(t);
dep[t]=0;gap[0]=1;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=first[u];i;i=nex[i])
{
int v=to[i];
if(dep[v]!=-1) continue;
dep[v]=dep[u]+1;
gap[dep[v]]++;
q.push(v);
}
}
}
inline int dfs(int u,int in)
{
if(u==t) return in;
int out=0;
for(int i=cur[u];i;i=nex[i])
{
cur[u]=i;
int v=to[i];
if(!w[i]||dep[v]!=dep[u]-1) continue;
int res=dfs(v,min(w[i],in-out));
w[i]-=res;
w[i^1]+=res;
out+=res;
if(in==out) return out;
}
gap[dep[u]]--;
if(!gap[dep[u]]) dep[s]=n*m+3;
dep[u]++;
gap[dep[u]]++;
return out;
}
void work()
{
bfs();
while(dep[s]<n*m+2)
{
memcpy(cur,first,sizeof(first));
ans+=dfs(s,1e9);
}
}
}
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
inline int id(int x,int y){return (x-1)*m+y;}
int main()
{
n=read(),m=read();
s=0,t=n*m+1;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
int x=read();
if(x==1) Add(s,id(i,j),1e9);
else if(x==2) Add(id(i,j),t,1e9);
for(int k=0;k<4;++k)
{
int xx=i+dx[k],yy=j+dy[k];
if(xx<1||yy<1||xx>n||yy>m) continue;
Add(id(i,j),id(xx,yy),1);
}
}
}
ISAP::work();
printf("%d",ans);
//end();
return 0;
}

该文不被密码保护。
浙公网安备 33010602011771号