UVa1600 习题6-5 巡逻机器人 (Patrol Robot,ACM/ICPC Hanoi 2006)

原题链接: UVa-1600

题目大意:

    模拟机器人要从一个m*n(m和n的范围都在1到20的闭区间内)的网格的左上角(1,1)走到右下角(m,n)。网格中的一些格子是空地,用0表示,其它格子是障碍,用1表示。机器人每次可以往四个方向走一格,但不能连续地穿越k( [0,20] )个障碍,求最短路长度。起点和终点保证是空地。

解题思路:

 本题是图的最短路径问题,理所当然的想到用广度优先搜搜(BFS),但是这道题和普通的求最短路径问题不太一样,该题中机器人可以连接穿过n个墙壁(厉害咯),而且每此到空地之后可以恢复穿墙次数(呼吸回血大法)。

 (代码二,WA)一开始写的时候在结构体添加了一个s属性来表示剩余穿墙次数,每次穿墙减一,到空地恢复。而且我也没有设vis数组来表示是否经过,直接在输入数组grid上进行表示。写完之后样例通过,但是总感觉不太对。然后我就去uDebug找了一组数据(1000多个。。。),然后果然还是出错了。但是我对比了一下大部分都是对的,错的基本上都是1(墙)特别多的情况。肉眼看的话(除了起点和终点,中间还有一个点,可以休息回血),明显是可以到终点的。但是程序输出-1。隐隐感觉可能是走的路线不对,但是转念一想BFS每个点都是最短路径怎么可能不对,所以很懵逼。

 后来在网上看了一个小伙伴的代码另一个小伙伴的分析明白了一点。该题需要添加一个三维的vis数组来表示是否走过。因为:但在这题中,机器人走路会有更多的分支选择,比如在走到同一点,有两种同一步数的走法,但是到达这一点所破除的障碍数量却不同,在这里我们需要选择障碍物更少的,因为很有可能在以后破除障碍能更快到达终点。(分析来自上边的小伙伴)

 (代码一,AC)结合小伙伴们的思路还有代码,这才把这道题AC。

代码:

代码一:

#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<cmath>
using namespace std;
const int MAXN = 20 + 10;
struct Node
{
	int r, c, d, s;
	Node() {}
	Node(int x, int y, int d = 0 ,int s = 0) :r(x), c(y), d(d), s(s) {}
};
int grid[MAXN][MAXN];
bool vis[MAXN][MAXN][MAXN];
int dr[4] = { 0,1,0,-1 };
int dc[4] = { 1,0,-1,0 };
int n, rows, cols, res;

bool inside(int r, int c)
{
	return r > 0 && r <= rows  && c > 0 && c <= cols;
}
int move()
{
	if(rows == 1 && cols == 1) return 0;
	queue<Node> q;
	q.push(Node(1,1,0,0));
	vis[1][1][0]=true;
	while (!q.empty())
	{
		Node rob = q.front(); q.pop();
		for (int i = 0; i < 4; i++)
		{
			int r = rob.r + dr[i];
			int c = rob.c + dc[i];
			int layer = rob.s;
			if (r == rows && c == cols) return rob.d + 1;
			if(grid[r][c])  layer++;
            else  layer=0;
			if(layer<=res&&!vis[r][c][layer]&&inside(r,c))
            {
                vis[r][c][layer]=true;
                q.push(Node(r,c,rob.d+1,layer));
            }
		}
	}
	return -1;
}
int main()
{
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);
	cin >> n;
	while (n--)
	{
		memset(vis,0,sizeof(vis));
		cin >> rows >> cols;
		cin >> res;
		for (int i = 1; i <= rows; i++)
			for (int j = 1; j <= cols; j++)
				cin >> grid[i][j];
		cout << move()<<endl;
	}
	return 0;
}

  代码二:

#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<cmath>

using namespace std;

bool inside(int x, int y);
int move();
const int MAXN = 20 + 10;

struct Node
{
	int r, c, d, s;
	Node() {}
	Node(int x, int y, int d = 0 ,int s = 0) :r(x), c(y), d(d), s(s) {}
};

int grid[MAXN][MAXN];
int dr[4] = { 0,1,0,-1 };
int dc[4] = { 1,0,-1,0 };
int n, rows, cols, res;

int main()
{
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);
	cin >> n;
	while (n--)
	{
		cin >> rows >> cols;
		cin >> res;
		for (int i = 1; i <= rows; i++)
			for (int j = 1; j <= cols; j++)
				cin >> grid[i][j];
		cout << move() << endl;
	}
	return 0;
}

int move()
{
	queue<Node> q;
	q.push(Node(1,1,0,res));
	grid[1][1] = -1;
	while (!q.empty())
	{
		Node rob = q.front(); q.pop();
		for (int i = 0; i < 4; i++)
		{
			int r = rob.r + dr[i];
			int c = rob.c + dc[i];
			if (r == rows && c == cols) return rob.d + 1;
			if (inside(r, c) && grid[r][c] != -1)
			{
				if (grid[r][c] == 1 && rob.s < 1)
					continue;
				else if (grid[r][c] == 1)
					q.push(Node(r, c, rob.d + 1, rob.s - 1));
				else
				{
					q.push(Node(r, c, rob.d + 1, res));
				}
				grid[r][c] = -1;
			}
		}
	}
	return -1;
}

bool inside(int r, int c)
{
	return r > 0 && r <= rows  && c > 0 && c <= cols;
}



已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页