hdu5093 Battle ships 二分图匹配

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5093
题目是给你一个n*m的图,图中有三种字符,*表示海洋,#表示冰山,o表示浮冰。浮冰和冰山不能放战舰,每一行一列只能放一艘战舰,除非两个战舰中间有冰山,问最多能放多少艘战舰?
这题和放炮台那个题类似(炮台:http://acm.hdu.edu.cn/showproblem.php?pid=1045)不过,那个题数据最大是4*4,而这个是50*50,炮台那个直接dfs一阵瞎搞,就过了,毕竟数据小,而这个就虚了。那晚上组队选ecfinal名额,看到这道题第一眼,就想瞎dfs肯定tle,应该是二分图匹配,之前刷贪心小练也遇到过炮台那道,不过没贪心,直接老套路dfs过,包括当初刷二分图匹配也是老套路dfs过,结果比赛遇到这个题,wr用贪心写过炮台,本来想这两道差不多,直接让他贪心写一发赶紧过,省的被别人追上,结果贪心贪了半个小时,交了一发wa,就懵逼了,lyq也追上我们了,唉,ecfinal也去不了了,~~(>_<)~~,还是怪自己懒,当初写那道炮台的时候不学二分匹配。。。
二分匹配建图,考虑到每一排#的两边不能都有*,所以遇到#可以将#后面的重新另起一行,列也是如此,这样就避免了冰山的阻挡,列同样也是如此。这样建图就好了~
代码:

#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int spot=1300+10;
const int edge=2500+10;
const int maxn=50+10;
const double pi=acos(-1.0);nage1
int col[spot][spot],row[spot][spot],head[spot],sizes=0,marry[edge];
bool b[edge];
char graph[maxn][maxn];
struct stu
{
    int to,next;
} a[edge];
void init()   //初始化
{
    sizes=0;
    memset(head,-1,sizeof(head));
    memset(marry,0,sizeof(marry));
}
void add_edge(int from,int to)  //邻接表
{
    a[sizes].to=to;
    a[sizes].next=head[from];
    head[from]=sizes++;
}
bool dfs(int u)  
{
    int k,v;
    for(k=head[u]; k+1; k=a[k].next)
    {
        v=a[k].to;
        if(!b[v])
        {
            b[v]=1;
            if(!marry[v]||dfs(marry[v]))
            {
                marry[v]=u;
                return 1;
            }
        }
    }
    return 0;
}
int max_match(int n) //匈牙利
{
    int ans=0,i;
    for(i=1; i<=n; i++)
    {
        memset(b,0,sizeof(b));
        ans+=dfs(i);
     }
    return ans;
}
int main()
{
    int nn,i,j;
    scanf("%d",&nn);
    while(nn--)
    {
        int n,m;
        init();
        scanf("%d%d",&n,&m);
        for(i=1; i<=n; i++)
        {
            for(j=1; j<=m; j++)
                cin>>graph[i][j];
        }
        int rownum=1,colnum=1;
        for(i=1; i<=n; i++,rownum++)//对行处理
            for(j=1; j<=m; j++)
            {
                if(graph[i][j]=='#'&&graph[i][j+1]!='#'&&j+1<=m)
                    rownum++;
                row[i][j]=rownum;
            }
        for(j=1; j<=m; j++,colnum++) //对列处理
            for(i=1; i<=n; i++)
            {
                if(graph[i][j]=='#'&&graph[i+1][j]!='#'&&i+1<=n)
                    colnum++;
                col[i][j]=colnum;
            }
        for(i=1; i<=n; i++)
            for(j=1; j<=m; j++)
                if(graph[i][j]=='*')
                    add_edge(row[i][j],col[i][j]); //建边
        printf("%d\n",max_match(rownum));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值