HDU 4859-海岸线(网络流_最小割)

海岸线

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 161    Accepted Submission(s): 90

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。

思路:要先对周围填充上一圈的“D”,然后变成了一个(n+2)*(m+2)的矩形。因为要求的都是相邻的匹配数,所以可以利用黑白染色转化成一个二分图模型,对于每对相邻的进行加边。

参考bin神的博客~写的很详细,不愧是final选手。

点击打开链接

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <set>
#include <queue>
#include <map>

using namespace std;
const int inf=0x3f3f3f3f;
int head[3010],num[3010],d[3010],pre[3010],cur[3010];
char mp[110][110];
int n,m,cnt,nv,s,t;
int jx[]={0,0,1,-1};
int jy[]={1,-1,0,0};
struct node
{
    int u,v,cap;
    int next;
}edge[10000010];

void add(int u, int v, int cap)
{
    edge[cnt].v=v;
    edge[cnt].cap=cap;
    edge[cnt].next=head[u];
    head[u]=cnt++;

    edge[cnt].v=u;
    edge[cnt].cap=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}

void bfs()
{
    memset(d,-1,sizeof(d));
    memset(num,0,sizeof(num));
    queue<int >q;
    q.push(t);
    d[t]=0;
    num[0]=1;
    while(!q.empty()) {
        int i;
        int u=q.front();
        q.pop();
        for(i=head[u]; i!=-1; i=edge[i].next) {
            int v=edge[i].v;
            if(d[v]==-1) continue;
            d[v]=d[u]+1;
            num[d[v]]++;
            q.push(v);
        }
    }
}

int isap()
{
    memcpy(cur,head,sizeof(cur));
    int flow=0, u=pre[s]=s, i;
    bfs();
    while(d[s]<nv) {
        if(u==t) {
            int f=inf, pos;
            for(i=s; i!=t; i=edge[cur[i]].v) {
                if(f>edge[cur[i]].cap) {
                    f=edge[cur[i]].cap;
                    pos=i;
                }
            }
            for(i=s; i!=t; i=edge[cur[i]].v) {
                edge[cur[i]].cap-=f;
                edge[cur[i]^1].cap+=f;
            }
            flow+=f;
            u=pos;
        }
        for(i=cur[u]; i!=-1; i=edge[i].next) {
            if(d[edge[i].v]+1==d[u]&&edge[i].cap)
                break;
        }
        if(i!=-1) {
            cur[u]=i;
            pre[edge[i].v]=u;
            u=edge[i].v;
        } else {
            if(--num[d[u]]==0) break;
            int mind=nv;
            for(i=head[u]; i!=-1; i=edge[i].next) {
                if(mind>d[edge[i].v]&&edge[i].cap) {
                    mind=d[edge[i].v];
                    cur[u]=i;
                }
            }
            d[u]=mind+1;
            num[d[u]]++;
            u=pre[u];
        }
    }
    return flow;
}

int main()
{
    int T,n, m, i, j;
    int tt=1;
    char str[110];
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);
        memset(mp,0,sizeof(mp));
        for(i=1;i<=n;i++)
        {
            scanf("%s",str);
            for(j=0;j<m;j++)
            {
                if(str[j]=='E')
                    mp[i][j+1]=2;
                else if(str[j]=='.')
                    mp[i][j+1]=1;
            }
        }
        cnt=0;
        s=0;
        t=(n+2)*(m+2)+1;
        nv=t+1;
        memset(head,-1,sizeof(head));
        for(i=0;i<=n+1;i++)
        {
            for(j=0;j<=m+1;j++)
            {
                if((i+j)%2==0)
                {
                    if(mp[i][j]==1)
                        add(i*(m+2)+j+1,t,inf);
                    else if(mp[i][j]==0)
                        add(s,i*(m+2)+j+1,inf);
                }
                else
                {
                    if(mp[i][j]==0)
                        add(i*(m+2)+j+1,t,inf);
                    else if(mp[i][j]==1)
                    {
                        add(s,i*(m+2)+j+1,inf);
                    }
                }
                for(int k=0;k<4;k++)
                {
                    int x=i+jx[k];
                    int y=j+jy[k];
                    if(x>=0&&x<=n+1&&y>=0&&y<=m+1)
                        add(i*(m+2)+j+1,x*(m+2)+y+1,1);
                }
            }
        }
        int ans;
        ans=isap();
        printf("Case %d: %d\n",tt++,(n+1)*(m+2)+(n+2)*(m+1)-ans);
    }
    return 0;
}
时间: 2024-12-17 21:40:55

HDU 4859-海岸线(网络流_最小割)的相关文章

HDU 4859(Bestcoder #1 1003)海岸线(网络流之最小割)

题目地址:HDU4859 做了做杭电多校,知识点会的太少了,还是将重点放在刷专题补知识点上吧,明年的多校才是重点. 这题题目求的最长周长,可以试想一下,这里的海岸线一定是在"."和"D"之间的,也就是说求最多的相邻的"."和"D"的配对对数.可以先转化成最小割求最小配对对数,因为总对数是一定的,只需要减去就行. 要先对周围填充上一圈的"D",然后变成了一个(n+2)*(m+2)的矩形.因为要求的都是相邻的匹

HDU 3452 Bonsai(网络流之最小割)

题目地址:HDU 3452 最小割水题. 源点为根节点.再另设一汇点,汇点与叶子连边. 对叶子结点的推断是看度数是否为1. 代码例如以下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include &l

POJ 3469-Dual Core CPU(网络流_最小割求容量)

PS:最小割第一发,我怎么感觉就是求最大流呢,sad.这是求最小割的容量的问题,根据最大流最小割定理,可以转换成求解网络流的最大流流量.这个事==最大流的. Dual Core CPU Time Limit: 15000MS   Memory Limit: 131072K Total Submissions: 19724   Accepted: 8562 Case Time Limit: 5000MS Description As more and more computers are equi

[bzoj2229][Zjoi2011]最小割_网络流_最小割树

最小割 bzoj-2229 Zjoi-2011 题目大意:题目链接. 注释:略. 想法: 在这里给出最小割树的定义. 最小割树啊,就是这样一棵树.一个图的最小割树满足这棵树上任意两点之间的最小值就是原图中这两点之间的最小割. 这个性质显然是非常优秀的. 我们不妨这样假设,我么已经把最小割树求出来了,那么这个题就迎刃而解了. 我们可以直接枚举点对,然后暴力验证就可以直接枚举出所有的合法点对是吧. 那么问题来了,我们如何才能求出所有的合法的点对? 这就需要用到了最小割树的构建过程. 我们最小割树的构

HDU 3046-Pleasant sheep and big big wolf(网络流_最小割)

Pleasant sheep and big big wolf Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2254    Accepted Submission(s): 946 Problem Description In ZJNU, there is a well-known prairie. And it attracts p

HDU 3046Pleasant sheep and big big wolf(网络流之最小割)

题目地址:HDU 3046 最小割第一发!其实也没什么发不发的...最小割==最大流.. 入门题,但是第一次入手最小割连入门题都完全没思路...sad..对最小割的本质还是了解的不太清楚.. 这题就是对每两个相邻的格子的边界都要进行加边,然后求最大流就OK了. RE了好长时间,注意遍历加边的时候要从1开始,而不是0开始,因为0是源点的...(也许只有我才犯这种错误吧...)建图不多说了..只要了解了最小割,建图还是很容易想的. 代码如下: #include <iostream> #includ

HDU 1565 &amp;&amp; HDU 1569 方格取数 (网络流之最小割)

题目地址:HDU 1565       HDU 1569 刚开始接触最小割,就已经感受到了最小割的博大精深... 这建图思路倒是好想..因为好多这种关于不相邻的这种网络流都是基本都是这样建图.但是感觉毫无道理可言...看了题解后才明白这样做的意义. 下面是题解中的说法. 大概是这样分析的,题义是要我们求在一个方格内取出N个点,使得这N个独立的(不相邻)点集的和最大.我们可以将问题转化为最小割来求解.首先,我们将方格进行黑白相间的染色,然后再将任意一种颜色(黑色)作为源点,一种颜色(白色)作为汇点

POJ 3469 Dual Core CPU(网络流之最小割)

题目地址:POJ 3469 建图思路:建源点与汇点,源点与CPU1相连,汇点与CPU2相连,对共享数据的之间连无向边. 我的ISAP过这题还是毫无时间压力的嘛... 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctyp

ZOJ 3792 Romantic Value(网络流之最小割)(找割边)

题目地址:ZOJ 3792 最小割做的太少..这题很明显是找割边.找割边就是判断正向弧是否是0.如果跑完一次最小割后正向弧流量为0的话,那就说明这个边为一条割边.但是找到了割边后再怎么办呢..中午睡觉的时候突然来了灵感..再利用这些割边求一次最大流不就行了..把割边的流量都设为1,其他的都为正无穷.那最后的流量就是最少需要的割边了.然后计算就可以了. 这次又把上限值直接设为sink+1了...导致WA了12发.....sad...以后得注意... 代码如下: #include <iostream