解题思路:通过曾经一个计数数组,将所有可到达该点位置的转弯次数更新为最小值,最后通过比较目的位置的转弯次数来判断是否能够到达。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
int f[4][2] = {{ -1, 0}, {1, 0}, {0, 1}, {0, -1}};
char Map[110][110];
int times[110][110];
const int MAXN = 10000;
struct pos {
int x, y;
int dir; //1,2,3,5,7
int step;
pos() {
step = MAXN;
}
};
bool BFS ( int m, int n, int k, int x1, int y1, int x2, int y2 ) {
pos tmp;
tmp.x = y1, tmp.y = x1;
tmp.dir = 1; //方向为任意方向
tmp.step = 0; //初始化起点转弯为0
times[tmp.x][tmp.y] = 0; //初始化起点转弯为0
queue<pos>Q;
Q.push ( tmp );
while ( !Q.empty() ) {
pos temp;
temp = Q.front();
Q.pop();
if ( temp.step > k ) {
continue;
}
for ( int i = 0; i < 4; i++ ) {
tmp.x = temp.x + f[i][0];
tmp.y = temp.y + f[i][1];
tmp.step = temp.step; //将当前节点次数化为跟前一个节点相同
if ( i == 0 )
tmp.dir = 2; //规定当前节点的方向
else if ( i == 1 )
tmp.dir = 3;
else if ( i == 2 )
tmp.dir = 5;
else
tmp.dir = 7;
if ( tmp.x >= 1 && tmp.x <= m && tmp.y >= 1 && tmp.y <= n && Map[tmp.x][tmp.y] == '.' ) {
if ( tmp.dir % temp.dir != 0 ) {
tmp.step = temp.step + 1; //方向不同增加转弯次数
}
if ( tmp.step > k )
continue; //次数过多,不入队
if ( times[tmp.x][tmp.y] >= tmp.step ) { //如果要走到的那个位置次数大于等于当前节点的次数入队,同时更新
times[tmp.x][tmp.y] = tmp.step;
Q.push ( tmp );
}
}
}
}
if ( times[y2][x2] <= k )
return true;
else
return false;
}
int main() {
int t;
cin >> t;
while ( t-- ) {
int m, n, k, x1, y1, x2, y2;
cin >> m >> n;
for ( int i = 0; i < m + 2; i++ ) {
for ( int j = 0; j < n + 2; j++ ) {
times[i][j] = MAXN;
}
}
for ( int i = 1; i <= m; i++ ) {
for ( int j = 1; j <= n; j++ ) {
cin >> Map[i][j];
}
}
cin >> k >> x1 >> y1 >> x2 >> y2;
if ( BFS ( m, n, k, x1, y1, x2, y2 ) ) {
cout << "yes" << endl;
}
else
cout << "no" << endl;
}
return 0;
}
/*
2
5 5
.....
.*.*.
.....
.*.*.
.....
1 1 1 3 4
这组样例会出现要走的该位置次数等于要扩展到的那个节点次数,这时需要
入队,因为以前扩展到该位置时,方向可能跟这次扩展到的方向不一致,会有次
数差异
*/
此题可以进一步改编,依靠已经搜出来的times数组引申到图论。