Problem Description
欢迎来到珠海!

由于土地资源越来越紧张,使得许多海滨城市都只能依靠填海来扩展市区以求发展。作为Z市的决策人,在仔细观察了Z市地图之后,你准备通过填充某些海域来扩展Z市的海岸线到最长,来吸引更多的游客前来旅游度假。为了简化问题,假设地图为一个N*M的格子,其中一些是陆地,一些是可以填充的浅海域,一些是不可填充的深海域。这里定义海岸线的长度为一个联通块陆地(可能包含浅海域填充变为的陆地)的边缘长度,两个格子至少有一个公共边,则视为联通。

值得注意的是,这里Z市的陆地区域可以是不联通的,并且整个地图都处在海洋之中,也就是说,Z市是由一些孤岛组成的,比如像,夏威夷?

你的任务是,填充某些浅海域,使得所有岛屿的海岸线之和最长。

Input
输入第一行为T,表示有T组测试数据。
每组数据以两个整数N和M开始,表示地图的规模。接下来的N行,每一行包含一个长度为M的字符串,表示地图,‘.’表示陆地,’E’表示浅海域,’D’表示深海域。

[Technical Specification]

1. 1 <= T <= 100
2. 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

对于第三组样例,一种可行方案是:

.E.
D.D
.E.

这样5个孤立小岛的海岸线总长为4 * 5 = 20。

 
 
 
 
【分析】
  网络流构图。
  最小割定理:最小割等于最大流。
  

因为E有两个选择D或者.   其实就暗含了最小割的模型。 最小割的话,就是一部分分到源点一侧,一部分分到汇点一侧。

如果把源点分在一起当成是.   和汇点分在一起当成是D.  那么建图的时候,相邻的建流量为1的边。 如果这个点本来是. 那个连汇点是INF,本来是D的,连源点是INF。

如果是这种建图的话,最小割求出来的最小周长。

我们需要的最大周长。

稍微转化下。 我们希望相邻格子不同的最多,其实就是要相邻格子相同的最少。

所以用最小割来求相邻格子相同的最小值,然后总相邻数减掉这个就是答案了。

建图方法就是一开始进行奇偶染色。相当于对于点(x,y)

如果(x+y)%2 == 0 那么当成这个格子是 . 的,和源点分在一起。

如果(x+y)%2 == 1 那么当成这个格子是 D 的,和汇点分在一起。

相邻两点都建边。

这样建图的话,如果在源点一侧的跑到了汇点一侧,那么就相当于这个点从.变到D, 自然相同的数量要减少了、

汇点一侧的跑到了源点一侧,那么就相当于这个点从D变成了.

建图的时候,如果(x+y)%2==0 && 这个点本来就是D  或者 (x+y)%2 == 1 && 这个点本来就是.     那么这个点必须和汇点在一起,就把这个点和源点连INF的边。 相反情况类似处理。

这样建图出来的最小割,一定就是相邻格子是同一类的最小数量。总相邻减掉这个值就是答案了。

 
 
  即如图所示:
 
  对于右边绿色的图的情况的(1,1)点和(1,2)点连边如图所示。(蓝色为边的编号,橙色为流量)
  上面棕色点为(1,1) 下面棕色点为(1,2)
    割边1表示点(1,1)为陆,割边2表示点(1,1)为海
    割边4表示点(1,2)为海,割边5表示点(1,2)为陆
  因为有双向边3,所以当两点同为陆或者海,必须把3号边也割了(花费1),图才能分割开。
  一开始假设所有有可能的(即不确定的)都是海岸线,建图跑最小割即可。
  注意相邻两点表示陆海的时候要反过来。
 
  网络流之前打的模版有点慢,导致我一直TLE,这样做会快一点:
 
AC代码如下:
 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define Maxn 4010
#define Maxm 4010*4
#define INF 0xfffffff char s[]; int map[][];
int dx[]={,-,,,},
dy[]={,,-,,};
int num[][];
int s1[][],s2[][]; struct node
{
int x,y,f,o,next;
}t[Maxm*];int len; int st,ed;
int dis[Maxn],first[Maxn]; int mymin(int x,int y) {return x<y?x:y;} void ins(int x,int y,int f)
{
if(f==) return;
t[++len].x=x;t[len].y=y;t[len].f=f;
t[len].next=first[x];first[x]=len;t[len].o=len+;
t[++len].x=y;t[len].y=x;t[len].f=;
t[len].next=first[y];first[y]=len;t[len].o=len-;
} queue<int > q;
bool bfs()
{
while(!q.empty()) q.pop();
memset(dis,-,sizeof(dis));
dis[st]=;q.push(st);
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=first[x];i;i=t[i].next) if(t[i].f>)
{
int y=t[i].y;
if(dis[y]==-)
{
dis[y]=dis[x]+;
q.push(y);
}
}
}
if(dis[ed]!=-) return ;
return ;
} int ffind(int x,int mmin)
{
if(x==ed) return mmin;
int r=;
for(int i=first[x];i;i=t[i].next) if(dis[t[i].y]==dis[x]+ && t[i].f>)
{
int y=t[i].y,a=mymin(t[i].f,mmin-r);
a=ffind(y,a);r+=a;
t[i].f-=a;
t[t[i].o].f+=a;
}
if(r==) dis[x]=-;
return r;
} int min_cut()
{
int a,ans=;
while(bfs()) ans+=ffind(st,INF);
return ans;
} int main()
{
int T,kase=,ans;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%s",s);
for(int j=;j<m;j++)
{
if(s[j]=='E') map[i][j+]=;
else if(s[j]=='.') map[i][j+]=;
else map[i][j+]=;
}
} int ans=*n*m+n+m;
for(int i=;i<=m+;i++) map[][i]=,map[n+][i]=;
for(int i=;i<=n+;i++) map[i][]=,map[i][m+]=; memset(s1,,sizeof(s1));
memset(s2,,sizeof(s2));
for(int i=;i<=n;i++)
for(int j=;j<=m;j++) if(map[i][j]!=)
{
int now=i*(m+)+j;
for(int k=;k<=;k++)
{
int nx=i+dx[k],ny=j+dy[k];
if(map[i][j]==) s1[nx][ny]++;
if(map[i][j]==) s2[nx][ny]++;
if((nx==||ny==||nx==n+||ny==m+)&&map[i][j]==) ans--;
else if(map[nx][ny]!=&&map[nx][ny]==map[i][j]&&k<=) ans--;
}
}
for(int i=;i<=m;i++) s2[][i]++,s2[n][i]++;
for(int i=;i<=n;i++) s2[i][]++,s2[i][m]++;
memset(first,,sizeof(first));
len=;int cnt=;
st=,ed=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++) if(map[i][j]==)
{
int now=++cnt;num[i][j]=cnt;
if((i+j)%==) {ins(now,ed,s2[i][j]);ins(st,now,s1[i][j]);}
else {ins(now,ed,s1[i][j]);ins(st,now,s2[i][j]);}
for(int k=;k<=;k++)
{
int nx=i+dx[k],ny=j+dy[k];
if(nx<||nx>n||ny<||ny>m) continue;
if(map[nx][ny]!=) continue;
int d=num[nx][ny];
ins(now,d,);ins(d,now,);
}
}
ans-=min_cut();
printf("Case %d: %d\n",++kase,ans);
}
return ;
}

[HDU4859]

2016-05-17 16:42:42

【HDU4859】 海岸线(网络流-最小割)的更多相关文章

  1. HDU4859 海岸线(最小割)

    题目大概就是说一个n*m的地图,地图上每一块是陆地或浅海域或深海域,可以填充若干个浅海域使其变为陆地,问能得到的最长的陆地海岸线是多少. 也是很有意思的一道题. 一开始想歪了,想着,不考虑海岸线重合的 ...

  2. 【题解】 bzoj3894: 文理分科 (网络流/最小割)

    bzoj3894,懒得复制题面,戳我戳我 Solution: 首先这是一个网络流,应该还比较好想,主要就是考虑建图了. 我们来分析下题面,因为一个人要么选文科要么选理科,相当于两条流里面割掉一条(怎么 ...

  3. 【bzoj3774】最优选择 网络流最小割

    题目描述 小N手上有一个N*M的方格图,控制某一个点要付出Aij的代价,然后某个点如果被控制了,或者他周围的所有点(上下左右)都被控制了,那么他就算是被选择了的.一个点如果被选择了,那么可以得到Bij ...

  4. 【bzoj1143】[CTSC2008]祭祀river Floyd+网络流最小割

    题目描述 在遥远的东方,有一个神秘的民族,自称Y族.他们世代居住在水面上,奉龙王为神.每逢重大庆典, Y族都会在水面上举办盛大的祭祀活动.我们可以把Y族居住地水系看成一个由岔口和河道组成的网络.每条河 ...

  5. 【bzoj1797】[Ahoi2009]Mincut 最小割 网络流最小割+Tarjan

    题目描述 给定一张图,对于每一条边询问:(1)是否存在割断该边的s-t最小割 (2)是否所有s-t最小割都割断该边 输入 第一行有4个正整数,依次为N,M,s和t.第2行到第(M+1)行每行3个正 整 ...

  6. 【bzoj1976】[BeiJing2010组队]能量魔方 Cube 网络流最小割

    题目描述 一个n*n*n的立方体,每个位置为0或1.有些位置已经确定,还有一些需要待填入.问最后可以得到的 相邻且填入的数不同的点对 的数目最大. 输入 第一行包含一个数N,表示魔方的大小. 接下来 ...

  7. 【bzoj4177】Mike的农场 网络流最小割

    题目描述 Mike有一个农场,这个农场n个牲畜围栏,现在他想在每个牲畜围栏中养一只动物,每只动物可以是牛或羊,并且每个牲畜围栏中的饲养条件都不同,其中第i个牲畜围栏中的动物长大后,每只牛可以卖a[i] ...

  8. 【bzoj3438】小M的作物 网络流最小割

    原文地址:http://www.cnblogs.com/GXZlegend/p/6801522.html 题目描述 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物 ...

  9. 【bzoj3144】[Hnoi2013]切糕 网络流最小割

    题目描述 输入 第一行是三个正整数P,Q,R,表示切糕的长P. 宽Q.高R.第二行有一个非负整数D,表示光滑性要求.接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤ ...

  10. 【bzoj3894】文理分科 网络流最小割

    原文地址:http://www.cnblogs.com/GXZlegend 题目描述 文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠结过) 小P所在的班级要进行文理分科.他的班级可以用 ...

随机推荐

  1. 隐藏TabBar是个累人的活

    最近进行跳转界面隐藏tabbar的时候遇到了一些坑,现在把它记录下来,如果有需要的朋友可以参考一下. 大家一般使用tabbar的时候,隐藏有两种方法. 一种是设置当前所处界面的隐藏属性 self.ta ...

  2. txt无法正常保存正文的解决办法

    最近遇到一个问题,txt文档中写了中文,则保存的时候 就会提示“该文件含有unicode格式字符,当文件保存为ANST编码文本文件时,该字符将会丢失”.虽然有解决办法,但不彻底,用起来总是很费劲,研究 ...

  3. 使用CSS的类名交集复合选择器

    首先先看一下基本定义: 复合选择器就是两个或多个基本选择器,通过不同方式连接而成的选择器,主要包括“交集”选择器.“并集”选择器.“后代”选择器. 交集选择器 “交集”复合选择器是由两个选择器直接连接 ...

  4. CSS伪类选择器和伪元素选择器

    CSS的伪类选择器常用的是link/visited/hover/active,分别对应未访问.已访问过.鼠标悬停.鼠标按下时的样式,常用于链接,使用时要按此顺序依次写CSS,不能乱 a:link{ba ...

  5. php 表单的活用

    一般表单都是用过POST 方式对数据进行隐秘的传输用, 可以偶尔你也会发现这样的用法,表单不止能够进行隐秘的传输.还能够进行URL的传输,并且是同时进行的 提交页面,在action 后面加了URL后缀 ...

  6. Apache Hadoop2.0之HDFS均衡操作分析

    1 HDFS均衡操作原理 HDFS默认的块的副本存放策略是在发起请求的客户端存放一个副本,如果这个客户端在集群以外,那就选择一个不是太忙,存储不是太满的节点来存放,第二个副本放在与第一个副本相同的机架 ...

  7. 使用原生JS编写ajax操作XMLHttpRequst对象

    ajax其本质就是XMLHttpRequest,现在jquery调用异步的方法很方便,但是也不能忘记原生的JS去编写ajax; 需要注意的是,很多人在写的时候喜欢只用XMLHttpRequest对象r ...

  8. sql脚本的格式

    创建表前先判断是否存在 IF OBJECT_ID(N'TableDataDictionary') IS NULL 存储过程头:--=================================== ...

  9. swift 遍历

    最简单的一个遍历数组 for 随便起个名字 in 升级 上面的看不懂的话,这个应该会简单点 import UIKit let interestingNumbers = [ ,,,,,], ,,,,,] ...

  10. 求最低分最高分---c#(冒泡排序的运用)

    // 输入10个人的分数,去掉两个最高两个最低,求平均分 Console.Write("请输入人数:"); int renshu = int.Parse(Console.ReadL ...