You are working for the International Company for Pool Construction, a construction company which specializes in building swimming pools. A new client wants to build several new pool areas. A pool area is a rectangular grid of w × h square patches, consisting of zero or more (possibly disconnected) pools. A pool consists of one or multiple connected hole patches, which will later be filled with water. In the beginning, you start with a piece of land where each patch is either a hole in the ground (’.’) or flat grass (’#’). In order to transform this land into a pool area, you must adhere to the following:
• You can leave a patch as it is. This costs nothing.
• If the patch is grass in the beginning, you can dig a hole there. This costs d EUR.
• If the patch is a hole in the beginning, you can fill the hole and put grass on top. This costs f EUR.
• You must place special boundary elements along each edge running between a final grass patch and a final hole patch, to ensure that water does not leak from the pool. This costs b EUR per boundary element.
• The outermost rows and columns of the pool area must always be grass.
You are given the task of calculating the cost of the cheapest possible pool area given the layout of the existing piece of land.
【题目分析】
网络流。
用流量去代表分割的代价。
【代码】
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define maxn (100005)
#define inf (0x3f3f3f3f)
int read()
{
int x=0,f=1; char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
int to[maxn],ne[maxn],h[maxn],fl[maxn],en=0,tt,d,f,b,S,T;
int map[51][51],n,m,hasher[51][51];
int mov[4][2]={{0,1},{1,0},{-1,0},{0,-1}};
void add(int a,int b,int c)
{
to[en]=b; ne[en]=h[a]; fl[en]=c; h[a]=en++;
to[en]=a; ne[en]=h[b]; fl[en]=0; h[b]=en++;
}
int mp[maxn];
bool tell()
{
memset(mp,-1,sizeof mp);
queue <int> q;
while (!q.empty()) q.pop();
q.push(S); mp[S]=0;
while (!q.empty())
{
int x=q.front(); q.pop();
for (int i=h[x];i>=0;i=ne[i])
{
if (fl[i]>0&&mp[to[i]]==-1)
{
mp[to[i]]=mp[x]+1;
q.push(to[i]);
}
}
}
if (mp[T]==-1) return false;
return true;
}
int zeng(int k,int now)
{
if (k==T) return now;
int ret=0;
for (int i=h[k];i>=0&&ret<now;i=ne[i])
{
if (fl[i]>0&&mp[to[i]]==mp[k]+1)
{
int tmp=zeng(to[i],min(now-ret,fl[i]));
fl[i]-=tmp; fl[i^1]+=tmp; ret+=tmp;
}
}
if (ret==0) mp[k]=-1;
return ret;
}
int main()
{
memset(h,-1,sizeof h);
tt=read();
while (tt--)
{
int ans=0;
memset(h,-1,sizeof h);en=0;
memset(map,0,sizeof map);
m=read();n=read();
d=read();f=read();b=read();
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
{
char ch=getchar();
while (ch!='#'&&ch!='.') ch=getchar();
if (ch=='#') map[i][j]=1;
}
// for (int i=1;i<=n;++i)
// {
// for (int j=1;j<=m;++j)
// printf("%d ",map[i][j]);
// printf("\n");
// }
int cnt=0;
for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) hasher[i][j]=++cnt;
S=0,T=++cnt;
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
{
if (map[i][j])
{
if (i==1||i==n||j==1||j==m)
add(S,hasher[i][j],inf);
else add(S,hasher[i][j],d);
}
else
{
if (i!=1&&i!=n&&j!=1&&j!=m) add(hasher[i][j],T,f);
else
{
add(S,hasher[i][j],inf);
ans+=f;
}
}
for (int k=0;k<4;++k)
{
int tx=i+mov[k][0],ty=j+mov[k][1];
if (tx>=1&&tx<=n&&ty>=1&&ty<=m)
add(hasher[i][j],hasher[tx][ty],b);
}
}
int tmp;
while (tell()) while (tmp=zeng(S,inf)) ans+=tmp;
printf("%d\n",ans);
}
}