1. 程式人生 > 其它 >[ZJOI2009] 狼和羊的故事

[ZJOI2009] 狼和羊的故事

link

題目大意

給定一個 \(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;
}