HDU 4859 海岸线(最大流最小割)

难得的中文题,就不翻译了。

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

题意:假设地图为一个N*M的格子,其中一些是陆地,一些是可以填充的浅海域,一些是不可填充的深海域。这里定义海岸线的长度为一个联通块陆地(可能包含浅海域填充变为的陆地)的边缘长度,两个格子至少有一个公共边,则视为联通。
值得注意的是,这里Z市的陆地区域可以是不联通的,并且整个地图都处在海洋之中,也就是说,Z市是由一些孤岛组成的,比如像,夏威夷?
你的任务是,填充某些浅海域,使得所有岛屿的海岸线之和最长。

输出最长海岸线和。

Solution:

一开始以为是贪心,后来发现这个规划问题好像不可以。算法是最小割,然后最小割==最大流,算法是最大流。

由于海岸线一定是海与岸的边界(废话哈哈哈~~~),不妨在给出的网格图外层加多层深海(的孤独~~~)

显然(i+j)%2==0的格子只可能和(i+j)%2==1的格子有海岸线。不妨二部图。

我们需要求的是最可能多的相邻不同对(<‘D‘, ‘.‘>),也就是求尽可能少的相邻相同对(<‘D‘, ‘D‘>或<‘.‘, ‘.‘>)。

建模如图,感觉这样画图比较直观。只画出部分,还有EE相连之类的。

左右流量均为inf,中间流量为1。

显然最大流跑出来的是最少的相同对数。

答案就是 sum - mf

#pragma comment (linker,"/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <stack>
using namespace std;

#define mxn 2600
#define mxe 26000
#define inf 0x3f3f3f3f
struct SAP{
	int dis[mxn],pre[mxn],gap[mxn],arc[mxn],f[mxe],cap[mxe];
	int head[mxn],nxt[mxe],vv[mxe],e;
	void init(){e=0;memset(head,-1,sizeof(head));}
	void addedge(int u,int v,int c){
		vv[e]=v,cap[e]=c,nxt[e]=head[u],head[u]=e++;
		vv[e]=u,cap[e]=0,nxt[e]=head[v],head[v]=e++;
	}
	int max_flow(int s,int t,int n){
		int q[mxn],j,mindis,ans=0,ht=0,tl=1;
		int u,v,low;
		bool found,vis[mxn];
		memset(dis,0,sizeof(dis));
		memset(gap,0,sizeof(gap));
		memset(vis,0,sizeof(vis));
		memset(arc,0,sizeof(arc));
		memset(f,0,sizeof(f));
		q[0]=t,vis[t]=true,dis[t]=0,gap[0]=1;
		while(ht<tl){
			int u = q[ht++];
			for(int i=head[u];i!=-1;i=nxt[i]){
				v = vv[i];
				if(!vis[v]){
					vis[v]=true;
					dis[v]=dis[u]+1;
					q[tl++]=v;
					gap[dis[v]]++;
					arc[v]=head[v];
				}
			}
		}
		u=s;low=inf;pre[s]=s;
		while(dis[s]<n){
			found = false;
			for(int &i = arc[u];i!=-1;i=nxt[i]){
				if(dis[vv[i]]==dis[u]-1 && cap[i]>f[i]){
					found = true; v=vv[i];
					low = min(low, cap[i]-f[i]);
					pre[v]=u;u=v;
					if(u==t){
						while(u!=s){
							u=pre[u];
							f[arc[u]]+=low;
							f[arc[u]^1]-=low;
						}
						ans+=low;low=inf;
					}
					break;
				}
			}
			if(found) continue;
			mindis = n;
			for(int i=head[u];i!=-1;i=nxt[i]){
				if(mindis>dis[vv[i]] && cap[i]>f[i]){
					mindis = dis[vv[j=i]];
					arc[u]=i;
				}
			}
			if(--gap[dis[u]]==0) return ans;
			dis[u] = mindis+1;
			gap[dis[u]]++;
			u=pre[u];
		}
		return ans;
	}
}sap;
char maze[55][55];
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
int main(){
    int t,n,m,ca=0;
    scanf("%d",&t);
    while(t--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i) scanf("%s",maze[i]+1);
		for(int i=0;i<=n+1;++i) maze[i][0]=maze[i][m+1]=‘D‘;
		for(int j=0;j<=m+1;++j) maze[0][j]=maze[n+1][j]=‘D‘;
		sap.init();
		int src = (n+2)*(m+2);
		int des = src+1;
		for(int i=0;i<=n+1;++i){
			for(int j=0;j<=m+1;++j){
				int u = i*(m+2)+j;
				if((i^j)&1){
					if(maze[i][j]==‘D‘) sap.addedge(u,des,inf);
					if(maze[i][j]==‘.‘) sap.addedge(src,u,inf);
				}else {
					if(maze[i][j]==‘.‘) sap.addedge(u,des,inf);
					if(maze[i][j]==‘D‘) sap.addedge(src,u,inf);
				}
				for(int k=0;k<4;++k){
					int ii=i+dx[k];
					int jj=j+dy[k];
					if(ii<0 || jj<0 || ii>n+1||jj>m+1) continue;
					int u = i*(m+2)+j;
					int v = ii*(m+2)+jj;
					sap.addedge(u,v,1);
				}
			}
		}
		int mf = sap.max_flow(src,des,des+1);
		int sum = (n+1)*(m+2)+(n+2)*(m+1);
		printf("Case %d: %d\n",++ca,sum-mf);
    }
    return 0;
}
时间: 2024-10-05 23:02:42

HDU 4859 海岸线(最大流最小割)的相关文章

HDU 4859 海岸线 最小割

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4859 题解: 这题考察的是最小割. 我们可以这样想:海岸线的长短变化都是E引起的,我们通过把’E'变成'.'或'D'来使海岸线最大化. 我们要算海岸线就是算格子‘.'和格子'D'(在原有地图周围四面都要加’D‘)相邻的面数,要使它最大,就是要使'.'与’.':'D'与'D'相邻的面数最小,而面数最小可以用最小割来做. 现在我们先把格子上的点黑白染色,(i+j)%2==1的为A类,为0的为B类, 在

HDU 4859 海岸线(最小割+最大独立点权变形)

http://acm.hdu.edu.cn/showproblem.php?pid=4859 题意: 欢迎来到珠海!由于土地资源越来越紧张,使得许多海滨城市都只能依靠填海来扩展市区以求发展.作为Z市的决策人,在仔细观察了Z市地图之后,你准备通过填充某些海域来扩展Z市的海岸线到最长,来吸引更多的游客前来旅游度假.为了简化问题,假设地图为一个N*M的格子,其中一些是陆地,一些是可以填充的浅海域,一些是不可填充的深海域.这里定义海岸线的长度为一个联通块陆地(可能包含浅海域填充变为的陆地)的边缘长度,两

hdu 4859 海岸线 Bestcoder Round 1

http://acm.hdu.edu.cn/showproblem.php?pid=4859 题目大意: 在一个矩形周围都是海,这个矩形中有陆地,深海和浅海.浅海是可以填成陆地的. 求最多有多少条方格线满足两侧分别是海洋和陆地 这道题很神 首先考虑一下,什么情况下能够对答案做出贡献 就是相邻的两块不一样的时候 这样我们可以建立最小割模型,可是都说是最小割了 无法求出最大的不相同的东西 所以我们考虑转化,用总的配对数目 - 最小的相同的对数 至于最小的相同的对数怎么算呢? 我们考虑这样的构造方法:

hdu 4859 最大点权独立集的变形(方格取数的变形)

/*刚开始不会写,最大点权独立集神马都不知道,在潘神的指导下终于做出来,灰常感谢ps: 和方格取数差不多奇偶建图,对于D必割点权为0,对于.必然不割点权为inf.然后和方格取数差不多的建图 .--.||E权值为2,,.||E--D权值为0. 最大点权独立集=sum-最小点权覆盖. */ #include<stdio.h> #include<string.h> #include<queue> using namespace std; #define inf 0x3ffff

[最短路,最大流最小割定理] 2019 Multi-University Training Contest 1 Path

题目:http://acm.hdu.edu.cn/showproblem.php?pid=6582 Path Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 3747    Accepted Submission(s): 1075 Problem Description Years later, Jerry fell in love

hihocoder 网络流二&#183;最大流最小割定理

网络流二·最大流最小割定理 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi:在上一周的Hiho一下中我们初步讲解了网络流的概念以及常规解法,小Ho你还记得内容么? 小Ho:我记得!网络流就是给定了一张图G=(V,E),以及源点s和汇点t.每一条边e(u,v)具有容量c(u,v).网络流的最大流问题求解的就是从s到t最多能有多少流量. 小Hi:那这个问题解决办法呢? 小Ho:解决网络流的基本思路就是寻找增广路,不断更新残留网络.直到找不到新的增广路,此时得到的

网络的最大流最小割定理

什么是流(flow): 在一个有向图中,只有出去的边没有进来的边的节点叫做源(source),只有进来的边没有出去的边的节点叫做汇(sink),其它的节点进来的边和出去的边应该是平衡的. 边上可以加权值,假设对于一个交通图来说,可以认为边上的权重为一条道路上的最大流量.那么对于图中任意两个节点来说,它们之间可以存在很多路径,每条路径上可以负载的最大流量应该是这条路径上权重最小的那条边所能承载的流量(联想一下“瓶颈”这个词,或者木桶理论),那么所有的路径上所负载流量之和也就是这两个节点之间多能通过

最大流最小割C++实现

最大流量问题:寻找从源点到汇点的最大流量. 使用最短增益路径法(或先标记先扫描法).这里标记意味着用两个记号来标记一个新的(为标记)的顶点:第一个标记指出从源点到被标记顶点还能增加多少流量:第二用来分别个标记指出另一个顶点的名字,就是从该顶点访问到被标记顶点的(对于源点来说这个标记可以不必指定).方便起见,也可以为第二个标记加上“+”或“-”符号,用来分别指出该顶点是通过前向边还是后向边访问到的.因此,源点可被标记为∞,-.对于其他顶点,按照以下方法计算它的标记: (1)如果为标记顶点j是由j到

【codevs1907】方格取数3(最大流最小割定理)

网址:http://codevs.cn/problem/1907/ 题意:在一个矩阵里选不相邻的若干个数,使这些数的和最大. 我们可以把它看成一个最小割,答案就是矩阵中的所有数-最小割.先把矩阵按国际象棋棋盘黑白染色(即把相邻的点分别染成白色和黑色),然后黑点连源点,白点连汇点.割掉一个点到源/汇的边就是不选择这个点,最后的目的就是使源到汇不连通(不引发题目不能选择位置相邻的数的矛盾). 然而最小割怎么求呢? 于是我们就要引入一个定理:最大流最小割定理.它的意思就是说,在一个图中,a点到b点的最