hdu 4859 海岸线 最小割
海岸线
题目连接:
http://acm.hdu.edu.cn/showproblem.php?pid=4859
Description
欢迎来到珠海!
由于土地资源越来越紧张,使得许多海滨城市都只能依靠填海来扩展市区以求发展。作为Z市的决策人,在仔细观察了Z市地图之后,你准备通过填充某些海域来扩展Z市的海岸线到最长,来吸引更多的游客前来旅游度假。为了简化问题,假设地图为一个N*M的格子,其中一些是陆地,一些是可以填充的浅海域,一些是不可填充的深海域。这里定义海岸线的长度为一个联通块陆地(可能包含浅海域填充变为的陆地)的边缘长度,两个格子至少有一个公共边,则视为联通。
值得注意的是,这里Z市的陆地区域可以是不联通的,并且整个地图都处在海洋之中,也就是说,Z市是由一些孤岛组成的,比如像,夏威夷?
你的任务是,填充某些浅海域,使得所有岛屿的海岸线之和最长。
Input
输入第一行为T,表示有T组测试数据。
每组数据以两个整数N和M开始,表示地图的规模。接下来的N行,每一行包含一个长度为M的字符串,表示地图,‘.’表示陆地,’E’表示浅海域,’D’表示深海域。
[Technical Specification]
- 1 <= T <= 100
- 1 <= N, M <= 47
Output
对每组数据,先输出为第几组数据,然后输出最长的海岸线长度。
Sample Input
3
2 2
EE
EE
3 3
EEE
.E.
EEE
3 3
EEE
DED
EEE
Sample Output
Case 1: 8
Case 2: 16
Case 3: 20
Hint
题意
题解:
题目很显然就是要求D和.相邻的边,个数最多,我们转换一下,就是求相邻的边相同的最少。
求最小割模型
黑白染色之后,E无视,如果黑色的.或者白色的D,我们就连S,否则连T,容量都是INF
这样建边后,如果要从源点流向汇点,那么肯定是.->.或者D->D
所以求最小割就好了
代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN=100000,MAXM=100000,inf=1e9;
struct Edge
{
int v,c,f,nx;
Edge() {}
Edge(int v,int c,int f,int nx):v(v),c(c),f(f),nx(nx) {}
} E[MAXM];
int G[MAXN],cur[MAXN],pre[MAXN],dis[MAXN],gap[MAXN],N,sz;
void init(int _n)
{
N=_n,sz=0; memset(G,-1,sizeof(G[0])*N);
}
void link(int u,int v,int c)
{
E[sz]=Edge(v,c,0,G[u]); G[u]=sz++;
E[sz]=Edge(u,0,0,G[v]); G[v]=sz++;
}
bool bfs(int S,int T)
{
static int Q[MAXN]; memset(dis,-1,sizeof(dis[0])*N);
dis[S]=0; Q[0]=S;
for (int h=0,t=1,u,v,it;h<t;++h)
{
for (u=Q[h],it=G[u];~it;it=E[it].nx)
{
if (dis[v=E[it].v]==-1&&E[it].c>E[it].f)
{
dis[v]=dis[u]+1; Q[t++]=v;
}
}
}
return dis[T]!=-1;
}
int dfs(int u,int T,int low)
{
if (u==T) return low;
int ret=0,tmp,v;
for (int &it=cur[u];~it&&ret<low;it=E[it].nx)
{
if (dis[v=E[it].v]==dis[u]+1&&E[it].c>E[it].f)
{
if (tmp=dfs(v,T,min(low-ret,E[it].c-E[it].f)))
{
ret+=tmp; E[it].f+=tmp; E[it^1].f-=tmp;
}
}
}
if (!ret) dis[u]=-1; return ret;
}
int dinic(int S,int T)
{
int maxflow=0,tmp;
while (bfs(S,T))
{
memcpy(cur,G,sizeof(G[0])*N);
while (tmp=dfs(S,T,inf)) maxflow+=tmp;
}
return maxflow;
}
char ss[120][120];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
int get(int x,int y)
{
return (x+1)*105+(y+1)+3;
}
int main()
{
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++)
{
int n,m;
init(50000);
memset(ss,0,sizeof(ss));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%s",ss[i]+1);
for(int i=0;i<=n+1;i++)
ss[i][0]=ss[i][m+1]='D';
for(int i=0;i<=m+1;i++)
ss[0][i]=ss[n+1][i]='D';
int s = 0,t = 1;
int temp = 0;
for(int i=0;i<=n+1;i++)
{
for(int j=0;j<=m+1;j++)
{
for(int t=0;t<4;t++)
{
int x = i+dx[t];
int y = j+dy[t];
if(x<0||x>n+1||y<0||y>m+1)continue;
link(get(i,j),get(x,y),1);
temp++;
}
if(ss[i][j]!='E')
{
if( ((i+j)%2 == 1 && ss[i][j] == '.') || ((i+j)%2 == 0 && ss[i][j] == 'D') )
link(s,get(i,j),inf);
else link(get(i,j),t,inf);
}
}
}
int now = dinic(s,t);
printf("Case %d: %d\n",cas,temp/2-now);
}
}