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;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rocky0429

一块也是爱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值