HDU 4859(Bestcoder #1 1003)海岸线(网络流之最小割)[通俗易懂]

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

大家好,又见面了,我是全栈君。

题目地址:HDU4859

做了做杭电多校,知识点会的太少了。还是将重点放在刷专题补知识点上吧,明年的多校才是重点。

这题题目求的最长周长。能够试想一下,这里的海岸线一定是在“.”和“D”之间的,也就是说求最多的相邻的“.”和“D”的配对对数。能够先转化成最小割求最小配对对数,由于总对数是一定的。仅仅须要减去即可。

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

二分图已经分成了X集和Y集两个子集合。如果要把全部的“.”都要分到X集,全部的”D”都要分到Y集(不过如果),这时候分两种情况讨论:

1:若当前点在地图上是 . 可是却被分到了Y集,或者当前点是 D ,却被分到了X集。就和源点连一条INF的边。

2:若当前点在地图上是 . 而且被分到了X集,或者当前点是 D ,被分到了Y集,就和汇点连一条INF的边。

分析一下就知道,仅仅有 . –> . 或者 D –> D ,也就是类型同样的。才干从源流向汇。

源连接的点是“分错了”的点( X集的D或者Y集的. ),汇连接的点是“分对了”的点(X集的.或者Y集的D),所以假设要从源流到汇,则一定是D->D或者.->.。也就是同样类型的,求出最小割就是最小化同样的。

最后用总对数减去这个就是答案.

代码例如以下:

#include <iostream>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <math.h>#include <ctype.h>#include <queue>#include <map>#include<algorithm>using namespace std;const int INF=0x3f3f3f3f;int head[3000], source, sink, nv, cnt;int cur[3000], num[3000], d[3000], pre[3000];int jx[]={0,0,1,-1};int jy[]={1,-1,0,0};struct node{    int u, v, cap, next;}edge[1000000];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(sink);    d[sink]=0;    num[0]=1;    while(!q.empty())    {        int u=q.front();        q.pop();        for(int i=head[u];i!=-1;i=edge[i].next)        {            int v=edge[i].v;            if(d[v]==-1)            {                d[v]=d[u]+1;                num[d[v]]++;                q.push(v);            }        }    }}int isap(){    memcpy(cur,head,sizeof(cur));    bfs();    int flow=0, u=pre[source]=source, i;    while(d[source]<nv)    {        if(u==sink)        {            int f=INF, pos;            for(i=source;i!=sink;i=edge[cur[i]].v)            {                if(f>edge[cur[i]].cap)                {                    f=edge[cur[i]].cap;                    pos=i;                }            }            for(i=source;i!=sink;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, mp[60][60], num=0;    char s[60];    scanf("%d",&t);    while(t--)    {        num++;        scanf("%d%d",&n,&m);        memset(mp,0,sizeof(mp));        for(i=1;i<=n;i++)        {            scanf("%s",s);            for(j=0;j<m;j++)            {                if(s[j]=='E')                    mp[i][j+1]=2;                else if(s[j]=='.')                    mp[i][j+1]=1;            }        }        cnt=0;        memset(head,-1,sizeof(head));        source=0;        sink=(n+2)*(m+2)+1;        nv=sink+1;        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,sink,INF);                    }                    else if(mp[i][j]==0)                    {                        add(source,i*(m+2)+j+1,INF);                    }                }                else                {                    if(mp[i][j]==0)                    {                        add(i*(m+2)+j+1,sink,INF);                    }                    else if(mp[i][j]==1)                    {                        add(source,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",num,(n+1)*(m+2)+(n+2)*(m+1)-ans);    }    return 0;}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/116023.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号