【玛丽有只小羔羊】题解

Link

题目描述:

玛丽是一个善良的小女孩,她养了一只可爱的小羔羊,有一天,小羔羊走丢了,这可急坏了玛丽!
听好心人告知,小羔羊迷失在一个N行M列的场景里(从上往下依次是1~ N行,地面为第N行,从左往右依次为1~M列)。最开始,玛丽站在地面上的,地面是一个连续无断点的平台,玛丽可以左右来回走。
玛丽有一把梯子,用于她上下平台(注意:梯子只能用于上下平台),玛丽是个女孩,所以下平台时她不会像男生那样鲁莽地跳下去,也得借助梯子,梯子可以无限次使用。也就是说:如果梯子的长度是L的话,玛丽可以从位置(i1, j) 爬到位置(i2, j),前提是两个位置都是平台,且fabs(i1 - i2) ≤ L。如图四可知,梯子太长了,玛丽携带不方便,她希望梯子越短越好,但是梯子太短,又不能到达某些必经的平台,矛盾啊~
请你帮助玛丽,求得一个能找到小羔羊的最短梯子长度。

在这里插入图片描述

输入格式:

第一行:2个整数N和M,表示场景大小。
接下来N行,每行M个字符,‘.’表示空中,大写的‘X’表示某平台。
最后一行:两个整数x,y,表示小羔羊所在的位置。小羔羊的位置保证是’X’。

输出格式:

1个整数,表示能找到小羔羊的最短梯子长度。

思路:

将玛丽找羊转化为羊到地面,这是等价且方便的。那么我们就以羊的坐标为起点,反向暴搜。

还需要先二分出梯子的长度,再进行 BFS。具体看注释。

Code:

#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
int n, m, sx, sy;
bool f[55][55], vis[55][55];
struct node {
	int x, y;	
};
bool bfs(int l) { // 思路是将问题转化成小羊通过梯子到达地面,反向暴搜 
	memset(vis, 0, sizeof(vis));
	queue<node> q; 
	q.push((node){sx, sy}); // 小羊的初始位置
	while(!q.empty()) {
		node p = q.front();
		q.pop();
		int dx = p.x, dy = p.y;
		// left
		dy --; // 左移 
		if(f[dx][dy] and !vis[dx][dy]) {
			vis[dx][dy] = 1;
			q.push((node){dx, dy});
		}
		// right 
		dy += 2; // 先回到原位,再向右移
		if(f[dx][dy] and !vis[dx][dy]) {
			vis[dx][dy] = 1;
			q.push((node){dx, dy});
		}
		dy --; // 恢复 
		// up
		for(int i = 1;i <= l; ++i) { // 从小到大,因为先到最近的地方 
			dx -= i;
			if(f[dx][dy] and !vis[dx][dy]) {
				vis[dx][dy] = 1;
				q.push((node){dx, dy});
				dx += i;
				break;
			}
			dx += i;
		} 
		// down
		for(int i = 1;i <= l; ++i) {
			dx += i;
			if(dx == n) return 1; // 到达地面,说明梯子长度符合
			if(f[dx][dy] and !vis[dx][dy]) {
				vis[dx][dy] = 1;
				q.push((node){dx, dy});
				dx -= i;
				break;
			}
			dx -= i;
		} 
	} 
	return 0;
}

int binary(int left, int right) {
	while(left <= right) { // 必须是小于等于,以免漏掉答案
		int mid = left + right >> 1;
		if(bfs(mid) and !bfs(mid - 1)) // 当前长度恰好可以,稍微小一点都不行
			return mid;
		else if(bfs(mid)) // 可以但不是最小
			right = mid;
		else left = mid + 1;// 长度偏小
	}
//  return left; 
    // 其实小于也是可以的,只需最后返回left
}
int main() {
	scanf("%d %d", &n, &m);
	for(int i = 1;i <= n; ++i) {
		scanf("%*c");
		for(int j = 1;j <= m; ++j) {
			char c = getchar();
			f[i][j] = (c == 'X' ? 1 : 0);
		}
	}
	scanf("%d %d", &sx, &sy);
	if(sx == n) {
		putchar('0');
		return 0;
	}
	printf("%d", binary(1, n - sx)); // 最大长度就是羊从当前台阶直接到地面 
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值