【HDU4859】 海岸线(网络流-最小割)

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。

【分析】

  网络流构图。

  最小割定理:最小割等于最大流。

  

  引用一段:http://www.kuangbin.net/archives/hdu4859

因为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代码如下:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 4010
  9 #define Maxm 4010*4
 10 #define INF 0xfffffff
 11
 12 char s[60];
 13
 14 int map[60][60];
 15 int dx[6]={0,-1,0,0,1},
 16     dy[6]={0,0,-1,1,0};
 17 int num[60][60];
 18 int s1[60][60],s2[60][60];
 19
 20 struct node
 21 {
 22     int x,y,f,o,next;
 23 }t[Maxm*2];int len;
 24
 25 int st,ed;
 26 int dis[Maxn],first[Maxn];
 27
 28 int mymin(int x,int y) {return x<y?x:y;}
 29
 30 void ins(int x,int y,int f)
 31 {
 32     if(f==0) return;
 33     t[++len].x=x;t[len].y=y;t[len].f=f;
 34     t[len].next=first[x];first[x]=len;t[len].o=len+1;
 35     t[++len].x=y;t[len].y=x;t[len].f=0;
 36     t[len].next=first[y];first[y]=len;t[len].o=len-1;
 37 }
 38
 39 queue<int > q;
 40 bool bfs()
 41 {
 42     while(!q.empty()) q.pop();
 43     memset(dis,-1,sizeof(dis));
 44     dis[st]=0;q.push(st);
 45     while(!q.empty())
 46     {
 47         int x=q.front();q.pop();
 48         for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
 49         {
 50             int y=t[i].y;
 51             if(dis[y]==-1)
 52             {
 53                 dis[y]=dis[x]+1;
 54                 q.push(y);
 55             }
 56         }
 57     }
 58     if(dis[ed]!=-1) return 1;
 59     return 0;
 60 }
 61
 62 int ffind(int x,int mmin)
 63 {
 64     if(x==ed) return mmin;
 65     int r=0;
 66     for(int i=first[x];i;i=t[i].next) if(dis[t[i].y]==dis[x]+1 && t[i].f>0)
 67     {
 68         int y=t[i].y,a=mymin(t[i].f,mmin-r);
 69         a=ffind(y,a);r+=a;
 70         t[i].f-=a;
 71         t[t[i].o].f+=a;
 72     }
 73     if(r==0) dis[x]=-1;
 74     return r;
 75 }
 76
 77 int min_cut()
 78 {
 79     int a,ans=0;
 80     while(bfs()) ans+=ffind(st,INF);
 81     return ans;
 82 }
 83
 84 int main()
 85 {
 86     int T,kase=0,ans;
 87     scanf("%d",&T);
 88     while(T--)
 89     {
 90         int n,m;
 91         scanf("%d%d",&n,&m);
 92         for(int i=1;i<=n;i++)
 93         {
 94             scanf("%s",s);
 95             for(int j=0;j<m;j++)
 96             {
 97                 if(s[j]==‘E‘) map[i][j+1]=0;
 98                 else if(s[j]==‘.‘) map[i][j+1]=1;
 99                 else map[i][j+1]=2;
100             }
101         }
102
103         int ans=2*n*m+n+m;
104         for(int i=0;i<=m+1;i++) map[0][i]=2,map[n+1][i]=2;
105         for(int i=0;i<=n+1;i++) map[i][0]=2,map[i][m+1]=2;
106
107         memset(s1,0,sizeof(s1));
108         memset(s2,0,sizeof(s2));
109         for(int i=1;i<=n;i++)
110          for(int j=1;j<=m;j++) if(map[i][j]!=0)
111          {
112              int now=i*(m+2)+j;
113              for(int k=1;k<=4;k++)
114              {
115                  int nx=i+dx[k],ny=j+dy[k];
116                  if(map[i][j]==1) s1[nx][ny]++;
117                  if(map[i][j]==2) s2[nx][ny]++;
118                  if((nx==0||ny==0||nx==n+1||ny==m+1)&&map[i][j]==2) ans--;
119                  else if(map[nx][ny]!=0&&map[nx][ny]==map[i][j]&&k<=2)    ans--;
120              }
121          }
122         for(int i=1;i<=m;i++) s2[1][i]++,s2[n][i]++;
123         for(int i=1;i<=n;i++) s2[i][1]++,s2[i][m]++;
124         memset(first,0,sizeof(first));
125         len=0;int cnt=2;
126         st=1,ed=2;
127         for(int i=1;i<=n;i++)
128          for(int j=1;j<=m;j++) if(map[i][j]==0)
129          {
130              int now=++cnt;num[i][j]=cnt;
131              if((i+j)%2==0) {ins(now,ed,s2[i][j]);ins(st,now,s1[i][j]);}
132              else {ins(now,ed,s1[i][j]);ins(st,now,s2[i][j]);}
133              for(int k=1;k<=2;k++)
134              {
135                  int nx=i+dx[k],ny=j+dy[k];
136                  if(nx<1||nx>n||ny<1||ny>m) continue;
137                  if(map[nx][ny]!=0) continue;
138                  int d=num[nx][ny];
139                  ins(now,d,1);ins(d,now,1);
140              }
141          }
142         ans-=min_cut();
143         printf("Case %d: %d\n",++kase,ans);
144     }
145     return 0;
146 }

[HDU4859]

2016-05-17 16:42:42

时间: 2024-09-29 22:45:51

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

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

题目描述 输入 第一行是三个正整数P,Q,R,表示切糕的长P. 宽Q.高R.第二行有一个非负整数D,表示光滑性要求.接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤P, 1≤y≤Q, 1≤z≤R). 100%的数据满足P,Q,R≤40,0≤D≤R,且给出的所有的不和谐值不超过1000. 输出 仅包含一个整数,表示在合法基础上最小的总不和谐值. 样例输入 2 2 2 1 6 1 6 1 2 6 2 6 样例输出 6 题目大意 给定一个p行q列的矩阵,每个位置可以

二分图&amp;网络流&amp;最小割等问题的总结

二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 带下界网络流 最小割问题的总结: *意义 1.加inf的边表示不能被割,通常用于体现某个点必须属于某个集合 连边(s,u,w)代表如果u不在s割的话需要付出代价w 2.连边(u,v,w)代表如果u在s割,v在t割需要付出代价w 但注意,如果u在t割,v在s割是不需要付出代价的. 那么如果连边(u,v,w)以及(v,u,w)则说明当u与v所属割不同的时候需要付出代价w *

HDU 2435 There is a war (网络流-最小割)

There is a war Problem Description There is a sea. There are N islands in the sea. There are some directional bridges connecting these islands. There is a country called Country One located in Island 1. There is another country called Country Another

【bzoj3630】[JLOI2014]镜面通道 对偶图+计算几何+网络流最小割

题目描述 在一个二维平面上,有一个镜面通道,由镜面AC,BD组成,AC,BD长度相等,且都平行于x轴,B位于(0,0).通道中有n个外表面为镜面的光学元件,光学元件α为圆形,光学元件β为矩形(这些元件可以与其他元件和通道有交集,具体看下图).光线可以在AB上任一点以任意角度射入通道,光线不会发生削弱.当出现元件与元件,元件和通道刚好接触的情况视为光线无法透过(比如两圆相切).现在给出通道中所有元件的信息(α元件包括圆心坐标和半径xi,yi,ri,β元件包括左下角和右上角坐标x1,y1,x2,y2

【bzoj2127】happiness 网络流最小割

题目描述 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值.作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大. 输入 第一行两个正整数n,m.接下来是六个矩阵第一个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择文科获得的喜悦值.第二个矩阵为n行m列 此矩阵的第i行

【bzoj2132】圈地计划 网络流最小割

题目描述 最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地.据了解,这块土地是一块矩形的区域,可以纵横划分为N×M块小区域.GDOI要求将这些区域分为商业区和工业区来开发.根据不同的地形环境,每块小区域建造商业区和工业区能取得不同的经济价值.更具体点,对于第i行第j列的区域,建造商业区将得到Aij收益,建造工业区将得到Bij收益.另外不同的区域连在一起可以得到额外的收益,即如果区域(I,j)相邻(相邻

ZOJ3792_Romantic Value(网络流/最小割=最大流/找割边)

解题报告 题目传送门 题意: 给出一个无向图,以及起点与终点.要删除一些边使得起点与终点不连通,在删掉边的权值之和最小的情况下要求删除的边数尽量少. 求出一个比值:剩余边数权值和/删除的边数. 思路: 明显的让起点终点达不到就是一个最小割,用最大流可以求出. 但是求割边边数就不会了,没做过最小割的求割边问题. 割边一定是残留网络中零流的边,但零流不一定是割边. 飞神的想法很奇特.链接传送 可以把残留网络的零流的边设成容量为1,其他设成无穷,再求一次最大流.最后流量一定等于割边边数 另外: 还有一

HDU 4289 Control (网络流-最小割)

Control Problem Description You, the head of Department of Security, recently received a top-secret information that a group of terrorists is planning to transport some WMD 1 from one city (the source) to another one (the destination). You know their

POJ3469_Dual Core CPU(网络流/最小割=最大流/模版)----Dinic模版2.0

解题报告 题目传送门 题意: 双核CPU,n个模块,每个模块必须运行在某个CPU核心上,每个模块在cpu单核的消耗A和B,M对模块要共享数据,如果在同一个核心上不用消耗,否则需要耗费.安排N个模块,使得总耗费最小 思路: 将两个cpu核心看成源点和汇点,其他模块分别与源点汇点连线(表示每个模块可以在任意cpu上运行),m对模块分别连双向边,要使得模块只能在一个cpu上运行,就是找到一个割,源点和汇点必不联通,耗费最少就是最小割,最小割最大流原理转换成求最大流. 这题数据大,没优化TLE了,加了两

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

题目描述 Mike有一个农场,这个农场n个牲畜围栏,现在他想在每个牲畜围栏中养一只动物,每只动物可以是牛或羊,并且每个牲畜围栏中的饲养条件都不同,其中第i个牲畜围栏中的动物长大后,每只牛可以卖a[i]元,每只羊可以卖b[i]元,为了防止牛羊之间相互影响,Mike找到了m条规律,每条规律给出一个三元组(i, j, k)表示如果第i个围栏和第j个围栏养的是不同的动物,那么Mike就需要花费k的代价请人帮忙处理牛羊之间的影响.不过同时Mike也发现k条特殊的规则(S, a, b),表示如果S中所有牲畜