题目概述
M
r
.
W
a
t
e
r
Mr.Water
Mr.Water的家是一个
N
×
M
N \times M
N×M 的方阵,其中 *
代表墙, .
代表地板, W
代表漏水的地方, M
代表
M
r
.
W
a
t
e
r
Mr.Water
Mr.Water, E
代表出口.
具体见原题
样例
输入(water05.in)
4 7
M.....E
**..*..
*W*..*.
......*
输出
Great!Only water!
分析
本题考查的是双向BFS
,每回合,先将Mr.Water扩展一层(遇水不扩展),表示可以走的地方,py同时遇到E
则return true;
然后在扩展W
,注意W
可以覆盖M
!
方式
伪代码:
X[]={0,1,0,-1}
Y[]={1,0,-1,0}
for i=0 ... 3 //方向
newx=nowx+X[i];
newy=nowy+Y[i];
if (mapp[newx][newy] == mapp[nowx][nowy])|(mapp[newx][newy] == 'W')|(!check(newx,newy))
continue; //只要是W或“我方”,就不扩展\
(check为越界与碰壁判断)
if mapp[newx][newy]=='E'
return true;
//扩展
mapp[newx][newy]=mapp[nowx][nowy];
分析
但是,还有两个问题:
- nowx与nowy怎么确定?
- check怎么写?
问题1解决:
我们可以定义一个结构体pos
,再定义一个队列,存放pos
,然后……好像有点
B
F
S
\blue{BFS}
BFS的感觉了
有感觉了,就套模板!
实现
伪代码:
X[]={0,1,0,-1}
Y[]={1,0,-1,0}
struct pos
int x;
int y;
pos()
pos(int _x,int _y)
x=_x;
y=_y;
pos +(const pos &b)
return pos(x+b.x,y+b.y);
queue<pos> q;
//假设已加入所有内容
while !q.empty()
nowp=q.pop();//注意是伪代码!
if (t == 1 && a[now.first][now.second] == 'W') || (!check(now))//如果越界或Mr.Water被淹……
continue;
for i=0 ... 3
newp=nowp+pos(X[i],Y[i]);
/*放上上面的代码(注意取舍)*/
mapp[newp.x][newp.y]=mapp[nowp.x][nowp.y];
q.push(newp);
问题2实现:
因为懒,就复制一下提交过的代码吧:
bool check(pos p){
if(p.x<=0||p.y<=0||p.x>n||p.y>m)return false;
if(mapp[p.x][p.y]=='*')return false;
return true;
}
分析
目前,还有1个问题:如何轮流扩散?
想法
首先,我想到了将每次扩展出的节点放入另一个队列中,等原来的队列空了之后在复制过来
又想到了stl_queue
可以整体赋值……
于是就有了函数bfs
(这回不是伪代码了):
queue<pos> que[2];
bool bfs(int type,char st,char ed='E')// type表示扩展的对象,0为水,1为Mr.Water\
st表示要扩展的值,ed表示终点\
作用:将type对应的值扩展一层
{
queue<pos> idx = que[type];//复制
while (!idx.empty())
{
pos now = idx.front();
idx.pop();
que[type].pop();// 原来的也要pop\
作用:清除原有的值
if ((t == 1 && a[now.x][now.y] == 'W') || (!check(now)))
continue;
for (int j = 0; j < 4; j++)
{
pos f=now+pos(decr[0][j],decr[1][j]);//重载运算符,妙啊!
if (!check(f.x, f.y) || a[f.x][f.y] == st || a[f.x][f.y] == 'W')
continue;
if (a[f.x][f.y] == ed)//ed是终点的值
return true;
a[f.x][f.y] = st;
que[type].push(f);//注意push的对象!!!!
}
}
return false;
}
至于solve1,肯定是轮流扩散:
bool solve()
{
while (!que[1].empty())
{
if (bfs(1, 'M'))//扩展Mr.Water
return true;
bfs(0, 'W', 0);//扩展水
}
return false;
}
优化
我们可以想一想,如果E
被W
覆盖,那么程序会 终止 还是会 继续执行 ?把鼠标放上去可获得正确答案
那怎么让程序在这种情况下终止呢?
代码
bool solve()// 改进后的solve\
你能看出那里变了吗?
{
while (!que[1].empty())
{
if (bfs(1, 'M'))
return true;
if(bfs(0,'W'))
return false;
}
return false;
}
由于输入不是程序主体,我几乎所有的代码都会省略输入,把主体放在一个叫solve的函数内,这样做是为了
方便防止大家直接复制 ↩︎