[bzoj4554]游戏——最大二分匹配 大佬们的博客 Some Links

Description:

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

思路:

好吧,虽然上课讲了这个题目,但是我并没有听懂,再回过头来看的话一开始我是这么想的:可以互相攻击到的边连一条边,求整个图的最大独立集。然后发现这不是个二分图,所以我不会求。。。
后来想起上课讲的,大概搞明白了。先考虑没有任何限制的放置炸弹,然后我们发现,当(i,j)放置了炸弹之后,第i行和第j列都不可以放了,即第i行只可以放一个炸弹,第j行也只可以放一个炸弹,于是可以把(i,j)看成以行为左边的点集和以列为右边的点集建立了一个二分图匹配,意义是在第i行第j列放置了一个炸弹,这样就不会再第i行和第j列重复选了。
对于有点限制的情况,硬石头就相当于割裂了这一行,这一行不互相影响,软石头就相当于不建立一条边。

/*=======================================
 * Author : ylsoi
 * Problem : bzoj4554
 * Algorithm : Graph Matching
 * Time : 2018.5.27
 * =====================================*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<climits>
using namespace std;
void File(){
    freopen("bzoj4554.in","r",stdin);
    freopen("bzoj4554.out","w",stdout);
}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define inf INT_MAX
const int maxn=50+10;
int n,m,cnt,b[maxn*maxn],beg[maxn*maxn];
int num1[maxn][maxn],num2[maxn][maxn],cnt1,cnt2,ans;
char s[maxn][maxn];
bool vis[maxn*maxn];
struct edge{int to,last;}E[maxn*maxn];
void add(int u,int v){
    ++cnt;
    E[cnt].to=v;
    E[cnt].last=beg[u];
    beg[u]=cnt;
}
void init(){
    scanf("%d%d",&n,&m);
    REP(i,1,n)scanf("%s",s[i]+1);
    REP(i,1,n){
        ++cnt1;
        REP(j,1,n){
            if(s[i][j]=='x')
                continue;
            if(s[i][j]=='#')
                ++cnt1;
            else if(s[i][j]=='*')
                num1[i][j]=cnt1;
        }
    }
    REP(j,1,m){
        ++cnt2;
        REP(i,1,n){
            if(s[i][j]=='x')
                continue;
            if(s[i][j]=='#')
                ++cnt2;
            else if(s[i][j]=='*')
                num2[i][j]=cnt2;
        }
    }
    REP(i,1,n){
        REP(j,1,m){
            if(s[i][j]=='x' || s[i][j]=='#')
                continue;
            add(num1[i][j],num2[i][j]);
        }
    }
}
bool dfs(int u){
    MREP(i,u){
        int v=E[i].to;
        if(vis[v])continue;
        vis[v]=1;
        if(!b[v] || dfs(b[v])){
            b[v]=u;
            return true;
        }
    }
    return false;
}
int main(){
    File();
    init();
    REP(i,1,cnt1){
        ans+=dfs(i);
        mem(vis);
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/80470582
今日推荐