原题链接: 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;
}