洛咕U294688水题题解

题目链接

题目概述

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.WaterE 代表出口.
具体见原题

样例

输入(water05.in)

4 7
M.....E
**..*..
*W*..*.
......*

输出

Great!Only water!

分析

本题考查的是双向BFS,每回合,先将Mr.Water扩展一层(遇水不扩展),表示可以走的地方,py同时遇到Ereturn 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];

分析

但是,还有两个问题:

  1. nowx与nowy怎么确定?
  2. 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;
}

优化

我们可以想一想,如果EW覆盖,那么程序会 终止 还是会 继续执行 ?把鼠标放上去可获得正确答案

那怎么让程序在这种情况下终止呢?

代码

bool solve()//	改进后的solve\
				你能看出那里变了吗?
{
	while (!que[1].empty())
	{
		if (bfs(1, 'M'))
			return true;
		if(bfs(0,'W'))
			return false;
	}
	return false;
}

  1. 由于输入不是程序主体,我几乎所有的代码都会省略输入,把主体放在一个叫solve的函数内,这样做是为了方便防止大家直接复制 ↩︎

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值