解题思路:既然找转向次数最少,没有限制移动几步,只要能到达终点即可,因此选择深度优先搜索,并且剪枝, 只要转向次数超过了k那就不再继续,这样只要到达终点就是答案。
但是还有个问题就是,每个方向走的时候怎么知道需不需要转向次数加一, 只需要加一个标记即可, 标记记录当前的方向, 如果下次走的方向跟现在相同就不加, 不同就加一。 表达式(nod.turn != i) 返回值为逻辑真假, 即0或1.
AC代码:
#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
struct NOD
{
int x, y;
int turn;
}nod;
int n, m, x1, y1, x2, y2, k;
int dx[] = {0,0,1,-1}, dy[] = {1,-1,0,0};
int turn[105][105];
char mp[105][105];
stack<NOD> st;
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
while(!st.empty()) st.pop(); //清空栈
for(int i=0; i<105; ++i)
for(int j=0; j<105; ++j) turn[i][j] = 100;//初始化数组
scanf("%d%d", &n, &m);
for(int i=1; i<=n; ++i) scanf("%s", mp[i]+1);
scanf("%d%d%d%d%d", &k, &y1, &x1, &y2, &x2);//题目先输入的列, 所以先y后x 转换成x代表行, y代表列
turn[x1][y1] = -1;//由于一开始是不计方向的所以是-1
int ok = 0;
for(st.push((NOD){x1, y1, -1}); !st.empty();)
{
nod = st.top();
st.pop();
//printf("~x = %d y = %d\n", nod.x, nod.y);
if(turn[nod.x][nod.y] > k) continue;//此时转向次数已经超过k, 不符合条件, 剪枝掉
if(nod.x == x2 && nod.y == y2)//找到终点
{
ok = 1;
break;
}
for(int i= 0; i<4; i++)//找四个的方向
{
int xx = nod.x + dx[i];
int yy = nod.y + dy[i];
if(xx > 0 && yy > 0 && xx <= n && yy <= m && mp[xx][yy] != '*' && turn[xx][yy] >= turn[nod.x][nod.y] + (nod.turn != i))//!=i的意思是说如果方向不同就加一
{
turn[xx][yy] = turn[nod.x][nod.y]+(nod.turn != i);
st.push((NOD){xx, yy, i});
}
}
}
if(ok) puts("yes");
else puts("no");
}
return 0;
}