【匈牙利】HDU5093[Battle ships]题解

来源:互联网 发布:js防水卷材和丙纶防水 编辑:程序博客网 时间:2024/05/23 13:25

题目概述

一张网格图,每个格子是海,浮冰或冰山,一只船(只占一个格子)只能放在海上。两只船放在同行同列需要满足他们之间至少有一座冰山。求最多能放多少船。

解题报告

一行一列只能放一个,一下就想到二分图最大匹配了,但是有障碍物,怎么办?其实问题的本质还是一样的,只不过我们需要这么处理:
这里写图片描述
由于出现了障碍物,“一行”和“一列”已经不能是原来意义上的一行和一列了。在同一行,如果被障碍物隔开,其实应该视作“多行”。也就是说我们可以把每个格子标两个号:“行”号和“列”号,障碍和浮冰处没有标号。在一行(一列)中,如果被障碍物隔开,就需要将之后的格子的标号+1,但被浮冰隔开则没有影响。这么处理之后,直接刷二分图最大匹配就行了。

示例程序

#include<cstdio>#include<cstring>using namespace std;const int maxn=50,maxm=50,maxt=maxn*maxm;int te,n,m,sumx,sumy,ans;char pic[maxn+5][maxm+5];int idx[maxn+5][maxm+5],idy[maxn+5][maxm+5];int E,lnk[maxt/2+5],who[maxt/2+5],son[maxt+5],nxt[maxt+5];bool vis[maxt/2+5];char getrch() {char ch=getchar();while (ch!='*'&&ch!='o'&&ch!='#') ch=getchar();return ch;}void make_x() //为行标号{    sumx=0;memset(idx,0,sizeof(idx));    for (int i=1,j=1;i<=n;i++,j=1)        while (j<=m)            {                for (;j<=m&&pic[i][j]=='#';j++);sumx+=j<=m;                for (;j<=m&&pic[i][j]!='#';j++)                    if (pic[i][j]=='*') idx[i][j]=sumx;            }}void make_y() //为列标号{    sumy=0;memset(idy,0,sizeof(idy));    for (int j=1,i=1;j<=m;j++,i=1)        while (i<=n)        {            for (;i<=n&&pic[i][j]=='#';i++);sumy+=i<=n;            for (;i<=n&&pic[i][j]!='#';i++)                if (pic[i][j]=='*') idy[i][j]=sumy;        }}void Add(int x,int y) {son[++E]=y;nxt[E]=lnk[x];lnk[x]=E;}bool Find(int x){    if (vis[x]) return false;vis[x]=true;    for (int j=lnk[x];j;j=nxt[j])        if (!who[son[j]]||Find(who[son[j]]))        {            who[son[j]]=x;            return true;        }    return false;}int main(){    freopen("program.in","r",stdin);    freopen("program.out","w",stdout);    scanf("%d",&te);    while (te--)    {        scanf("%d%d",&n,&m);        for (int i=1;i<=n;i++)        for (int j=1;j<=m;j++)            pic[i][j]=getrch();        make_x();make_y();        E=0;memset(lnk,0,sizeof(lnk));        for (int i=1;i<=n;i++)        for (int j=1;j<=m;j++)            if (idx[i][j]&&idy[i][j]) //i,j放船意味着idx[i][j]->idy[i][j]                Add(idx[i][j],idy[i][j]);        ans=0;memset(who,0,sizeof(who));        for (int i=1;i<=sumx;i++) //最大匹配            memset(vis,0,sizeof(vis)),ans+=Find(i);        printf("%d\n",ans);    }    return 0;}
原创粉丝点击