HDU 1547 Bubble Shooter(BFS)
http://acm.hdu.edu.cn/showproblem.php?pid=1547
题意:
如下图的游戏,R*C的棋盘格局,左上角是第1行1列,其中奇数行可以放C个不同颜色的气球,偶数行可以放C-1个不同颜色的气球.且如果我们新打一个气球到给定位置,>=3个相连的同颜色气球会爆炸,且如果某一块气球没有和最顶端的墙想连也会爆炸.
现在给出了当前气球的布局,以及最近一次射击的气球在布局中的位置,问你这次有多少个气球会爆炸。
分析:
大致思想是先用BFS从新气泡点走相同的颜色,且记录走过的点并把该点置为空(E),然后最终如果相同颜色气球数<3的话,就还原气球颜色。这样就找出了同色相连球的数目。
下一步找悬空球的数目:从顶端非空的格子遍历,每遍历一个气球就把该点置为E,然后朝它的6个方向继续BFS即可。返回本次遍历所消除的气球数(其实就是还剩下的气球数)。最后用初始的气球总数减去我们C次BFS的返回值之和,就是悬空的气球个数。
注意:球可以往6个方向走,且奇数和偶数行的球走法不同.
写代码的时候出了很多小错误,其中有一个是:原题中的偶数行和奇数行处理不同,但是由于代码中我们是从0开始算行数的,导致了原题的偶数行变成了奇数行,原题的奇数行变成了偶数行.
AC代码:
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=105;
int R,C;
char map[maxn][maxn];
int dir[2][6][2]=
{
{{0,-1},{0,1},{-1,0},{1,0},{-1,1},{1,1} }, //偶数行:左 右 左上 左下 右上 右下
{{0,-1},{0,1},{-1,-1},{1,-1},{-1,0},{1,0} } //奇数行:左 右 左上 左下 右上 右下
};
int BFS(bool flag,int sr,int sc)//flag=true时,表消除新球的同色球,否则表消除相连的所有球
{
int sum=0, s[maxn*maxn]; //错误,s数组开小了
queue<int> Q;
Q.push(sr*C+sc);
char ch=map[sr][sc]; //记录我们消除的初始颜色
map[sr][sc]='E'; //置空
s[sum++]=sr*C+sc; //记录被置空的点
while(!Q.empty())
{
int pos=Q.front();Q.pop();
int r=pos/C, c=pos%C;
for(int d=0;d<6;d++)
{
int nr=r+dir[(r+1)%2][d][0], nc=c+dir[(r+1)%2][d][1];
if(nr<0||nr>=R||nc<0||nc>=C-nr%2||map[nr][nc]=='E') continue;//错误,这里忘了nc>=C-nr%2 且我们行数是从0开始算的
if(flag && map[nr][nc]!=ch) continue;
map[nr][nc]='E';
Q.push(nr*C+nc);
s[sum++]=nr*C+nc;
}
}
if(flag && sum<3) for(int i=0;i<sum;i++) map[s[i]/C][s[i]%C]=ch; //sum<3,还原球状态
return sum;
}
int main()
{
int sr,sc;
while(scanf("%d%d%d%d",&R,&C,&sr,&sc)==4)
{
sr--,sc--; //错误,这里忘了
for(int i=0;i<R;i++) scanf("%s",map[i]);
int all=0;//初始总球数
for(int i=0;i<R;i++)
for(int j=0;map[i][j];j++)if(map[i][j]>='a'&&map[i][j]<='z')
all++;
BFS(true,sr,sc);
int ans=0;
for(int j=0;j<C;j++)if(map[0][j]!='E') //错误,这里只处理第0行
ans+=BFS(false,0,j);
printf("%d\n",all-ans);
}
return 0;
}