【Tjoi2016&Heoi2016】【BZOJ 4554】【JZOJ 4612】游戏

Description

在2016年,佳缘姐姐喜欢上了一款游戏,叫做泡泡堂。简单的说,这个游戏就是在一张地图上放上若干个炸弹,看
是否能炸到对手,或者躲开对手的炸弹。在玩游戏的过程中,小H想到了这样一个问题:当给定一张地图,在这张
地图上最多能放上多少个炸弹能使得任意两个炸弹之间不会互相炸到。炸弹能炸到的范围是该炸弹所在的一行和一
列,炸弹的威力可以穿透软石头,但是不能穿透硬石头。给定一张n*m的网格地图:其中*代表空地,炸弹的威力可
以穿透,可以在空地上放置一枚炸弹。x代表软石头,炸弹的威力可以穿透,不能在此放置炸弹。#代表硬石头,炸
弹的威力是不能穿透的,不能在此放置炸弹。例如:给出1*4的网格地图xx,这个地图上最多只能放置一个炸弹
。给出另一个1*4的网格地图x#,这个地图最多能放置两个炸弹。现在小H任意给出一张n*m的网格地图,问你最
多能放置多少炸弹

Solution

看起来像搜索或贪心,但实际是网络流二分图最大匹配,
先把整个矩阵的边缘打上#,
我们把每个*点视为左边的#与上边的#的一条边,因为每段没有阻挡的区间只允许一个炸弹,
最后用匈牙利算法做一遍二分图最大匹配即可

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define H(i,j) ((i)*(m+1)+j)
#define link(q,w) b[q][++b[q][0]]=w
using namespace std;
const int N=55*55;
int n,m,ans,I;
int b[N][N],zx[N];
int z[N];
char a[55][55];
bool OK(int q)
{
    if(z[q]>=I)return 0;
    z[q]=I;
    fo(i,1,b[q][0])
    {
        if(!zx[b[q][i]]||OK(zx[b[q][i]])){zx[b[q][i]]=q;return 1;}
    }
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    fo(i,1,n)a[i][0]=a[0][i]='#';
    fo(i,1,n)fo(j,1,m)
    {
        char ch=' ';
        while(ch!='*'&&ch!='x'&&ch!='#')ch=getchar();
        a[i][j]=ch;
        if(ch=='*')
        {
            int I,J;
            for(I=i-1;a[I][j]!='#';I--);
            for(J=j-1;a[i][J]!='#';J--);
            link(H(i,J),H(I,j));
        }
    }
    I=0;
    fo(i,1,n)fo(j,0,m)if(a[i][j]=='#')
    {
        I++;
        if(OK(H(i,j)))ans++;
    }
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值