HDU5093 Battle ships (BZOJ4554)

本文介绍了一种基于二分图的最大匹配算法实现方案,通过处理特定矩阵来解决船只放置问题。具体步骤包括构建行和列的独立编号,形成二分图,并运用搜索算法找到最优匹配,最终求得最多可放置船只的数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二分图最大匹配

题目传送门HDU

题目传送门BZOJ

因为两个差不多,这里只写HDU的。交BZOJ的话把t给删了就行。

题目大意:给你n*m的一个图,其中‘*’表示正常海面,‘#’表示冰山,‘o’表示浮冰。你要放尽可能多的船。船不能放在浮冰或冰山上。同一行同一列只能放一条船,除非中间有冰山隔着。输出最多能放的船的数量。

思路:先只考虑行的情况,把每只战船影响的范围称为一个”块“。给每一个块编号,把结果保存在一个二维数组中。x[i][j]存坐标为i,j的编号。列的话同样做,存在另一个数组中。
我们可以把行看成A集合,把列看成B集合。然后就可以愉快的连边啦。连完边后最多能放的船的数量就相当于跑一个最大匹配就可以啦。

贴上代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct edge{
    int next;
    int to;
};
edge a[2505];
int t,n,m,k,nx,sum;
int x[55][55],y[55][55];
int h[1255],who[1255];
char c[55][55];
bool f[1255];
void build_x(int i){
    bool flag=true;
    for (int j=0;j<m;j++){
        if (c[i][j]=='*'){
            if (flag) { sum++; flag=false; }
            x[i][j]=sum;
        }
        if (c[i][j]=='#')
            flag=true;
    }
}
void build_y(int i){
    bool flag=true;
    for (int j=0;j<n;j++){
        if (c[j][i]=='*'){
            if (flag) { sum++; flag=false; }
            y[j][i]=sum;
        }
        if (c[j][i]=='#')
            flag=true;
    }
}
void read(int u,int v){
    k++;
    a[k].next=h[u];
    a[k].to=v;
    h[u]=k;
}
bool dfs(int i){
    if (f[i])
        return false;
    f[i]=true;
    for (int j=h[i];j;j=a[j].next){
        if (!who[a[j].to]||dfs(who[a[j].to])){
            who[a[j].to]=i;
            return true;
        }
    }
    return false;
}
int main(){
    scanf("%d",&t);
    while (t--){
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        memset(h,0,sizeof(h));
        memset(who,0,sizeof(who));
        k=0;
        scanf("%d%d",&n,&m);
        for (int i=0;i<n;i++)
            scanf("%s",c[i]);
        sum=0;
        for (int i=0;i<n;i++)
            build_x(i);
        nx=sum;
        sum=0;
        for (int i=0;i<m;i++)
            build_y(i);
        for (int i=0;i<n;i++)
            for (int j=0;j<m;j++)
                if (x[i][j]!=0&&y[i][j]!=0)
                    read(x[i][j],y[i][j]);
        int ans=0;
        for (int i=1;i<=nx;i++){
            memset(f,false,sizeof(f));
            if (dfs(i))
                ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值