BZOJ 4554: [Tjoi2016&Heoi2016]游戏
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 951 Solved: 572
[Submit][Status][Discuss]
Description
在2016年,佳缘姐姐喜欢上了一款游戏,叫做泡泡堂。简单的说,这个游戏就是在一张地图上放上若干个炸弹,看
是否能炸到对手,或者躲开对手的炸弹。在玩游戏的过程中,小H想到了这样一个问题:当给定一张地图,在这张
地图上最多能放上多少个炸弹能使得任意两个炸弹之间不会互相炸到。炸弹能炸到的范围是该炸弹所在的一行和一
列,炸弹的威力可以穿透软石头,但是不能穿透硬石头。给定一张n*m的网格地图:其中*代表空地,炸弹的威力可
以穿透,可以在空地上放置一枚炸弹。x代表软石头,炸弹的威力可以穿透,不能在此放置炸弹。#代表硬石头,炸
弹的威力是不能穿透的,不能在此放置炸弹。例如:给出1*4的网格地图xx,这个地图上最多只能放置一个炸弹
。给出另一个1*4的网格地图x#,这个地图最多能放置两个炸弹。现在小H任意给出一张n*m的网格地图,问你最
多能放置多少炸弹
Input
第一行输入两个正整数n,m,n表示地图的行数,m表示地图的列数。1≤n,m≤50。接下来输入n行m列个字符,代表网
格地图。*的个数不超过n*m个
Output
输出一个整数a,表示最多能放置炸弹的个数
Sample Input
4 4
#***
*#**
**#*
xxx#
Sample Output
5
解题思路
二分图匹配,将行与列连边,要注意硬石头会将一行或一列分开,要分别计算。
代码
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<cstdlib> using namespace std; const int MAXN = 55; int head[MAXN*MAXN],cnt,num,ans,vis[MAXN*MAXN]; int to[MAXN*MAXN<<2],nxt[MAXN*MAXN<<2],tot; int n,m,match[MAXN*MAXN],id[MAXN][MAXN]; char c[MAXN][MAXN]; inline void add(int bg,int ed){ to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt; } bool dfs(int x){ for(register int i=head[x];i;i=nxt[i]){ int u=to[i]; if(vis[u]!=num){ vis[u]=num; if(!match[u] || dfs(match[u])){ match[u]=x; return true; } } } return false; } int main(){ scanf("%d%d",&n,&m); for(register int i=1;i<=n;i++) scanf("%s",c[i]+1); // for(register int i=1;i<=n;i++){ // for(register int j=1;j<=m;j++) // cout<<c[i][j]; // cout<<endl; // } for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++){ if(c[i][j]=='#' || c[i][j]=='x') continue; tot++;int k=j; while(c[i][k]!='#' && k<=m) id[i][k++]=tot; j=k-1; } for(register int i=1;i<=m;i++) for(register int j=1;j<=n;j++){ if(c[j][i]=='#' || c[j][i]=='x') continue; tot++;int k=j; while(c[k][i]!='#' && k<=n) { if(id[k][i] && c[k][i]!='x') add(id[k][i],tot); k++; } j=k-1; } for(register int i=1;i<=tot;i++){ num++; if(dfs(i)) ans++; }cout<<ans<<endl; return 0; }