uva1600 Patrol Robot(不同的BFS最短路)
uva1600 原题链接:https://vjudge.net/problem/UVA-1600
解析:
这题很明显用BFS最短路来做(当然也有其他方法)。但是这题的BFS略有不同,和普通BFS(以下普通BFS均为此意)最大的区别在于:普通BFS能走的路是通路,一个子节点只能属于一个父节点,而本题可以跨越障碍。也就是说,走已经走过的点也可能是最优解(普通BFS走已经走过的点必然不是最优解)。这就导致了一个子节点可能属于多个父节点(从树的角度来看)。
详细的讲:
普通BFS的结点只有两种情况,通或者不通;因此必然存在一个树可以连通所有通路结点,因此可以求出最短路径。
本题则不然,本题至少有三种状态:通,有障碍但是可以走(即在k范围内),不通;因此不能单纯的连成一个二叉树,而是要连成一个图,在图中找最短路(图与树的区别见离散数学)。
解题策略:
就本题来讲,在普通的BFS的基础上,去掉 判别 是否访问过当前结点 的数组;增加一个数组 用来存储当前结点还能跨过几个障碍(由于BFS的特性,到同一个结点的步数必然是相同的,但是它跨过的障碍数可能不同)。可以知道,当然是已经跨越的障碍越少越好(即还可以跨越障碍的机会(以下用k表示)越多越好,因为之后可能还有障碍,这样就可以跨过更多的障碍)。因此每到一个结点,判断当前走法所剩的k值,如果小于当前结点的值(即之前走法有更大的k),就舍弃。
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
int m,n,k;
const int maxn = 25;
int Map[maxn][maxn];
int dr[] = {1,0,-1,0};
int dc[] = {0,1,0,-1};
int bushu[maxn][maxn];//用来存放当前结点最大的 剩余的 跨障机会,即k
struct Node{
int step;
int r,c,k;
Node(int r,int c,int k,int step = 0):r(r),c(c),k(k),step(step){}
};
int main()
{
int t;
cin >> t;
while(t--){
memset(bushu,-1,sizeof(bushu));
int min_step = 999;
cin >> m >> n;
cin >> k;
for(int i = 0;i < m;i++)
for(int j = 0;j < n;j++) cin >> Map[i][j];
queue<Node> q;
q.push(Node(0,0,k));
while(!q.empty()){
Node a = q.front();
q.pop();
if(a.r == m-1 && a.c == n-1){
min_step = a.step;
break;
}
for(int i = 0;i < 4;i++){
int r = a.r + dr[i];
int c = a.c + dc[i];
int step = a.step;
if(r < 0 || r >= m || c < 0 || c >= n) continue;
if(bushu[r][c] >= a.k) continue;
else bushu[r][c] = a.k;
if(Map[r][c] == 0)
q.push(Node(r,c,k,step+1));
else if(a.k) q.push(Node(r,c,a.k-1,step+1));
}
}
if(min_step == 999) cout << -1 << endl;
else cout << min_step << endl;
}
return 0;
}
以上均为本人个人总结,不足之处请与我讨论,谢谢!