题意:给出一个起点,一个终点,规定的转弯次数,问能否在规定的转弯次数内到达终点---
这一题是学(看)习(题)的(解)@_@
主要学了两个地方
一个是剪枝,如果搜到的当前点的转弯次数小于该点turn数组记录下来的转弯次数,才有必要将它加入队列。
另一个是记录转弯方向 在结构体里面定义一个turn来记录转弯的个数,用dir来记录当前所在的方向(因为搜的时候是四个方向dir[4][2]来搜的,直接用i确定当前方向即可)
想想自己第一次做的时候的doubi想法,用dfs做,然后dfs(x,y,px,py),再判断由(x+dir[i][0],y+dir[i][1])与(x,y)构成的直线斜率和(x,y)和(px,py)构成的斜率乘积是否为-1-----果断没有写对----
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int turn[][];
int n,m,k;
int dir[][]={{,},{-,},{,},{,-}};
char map[][];
struct node
{
int x,y;
int turn,dir;//用turn来记录转弯的个数,用dir来记录当前的方向
} st,en,now,next;
queue<node>q;
void bfs()
{
while(!q.empty()) q.pop();
now.x=st.x;now.y=st.y;now.dir=-;now.turn=;//初始的方向可以定义为任意一个后来不会出现的方向
turn[now.x][now.y]=; //在起点时可以转向任意方向,令为0
q.push(now);
while(!q.empty())
{
now=q.front();q.pop(); for(int i=;i<;i++)
{
next.x=now.x+dir[i][];
next.y=now.y+dir[i][];
next.dir=now.dir;
next.turn=now.turn;
if(now.x==en.x&&now.y==en.y&&now.turn<=k)
{
printf("yes\n");
return;
}
if(next.x<||next.x>m||next.y<||next.y>n||map[next.x][next.y]=='*') continue;//第一次剪枝
if(next.dir!=i&&next.dir!=-) //如果当前方向和起始不同,则turn++
next.turn++;
if(next.turn>k) continue;//第二次剪 枝,转弯次数超过了,则剪枝
if(next.x==en.x&&next.y==en.y&&next.turn<=k)
{
printf("yes\n");
return;
} if(next.turn<=turn[next.x][next.y])//第三次剪枝,如果当前转弯的个数小于当前点的转弯个数,才有继续搜索的必要
{
next.dir=i;
turn[next.x][next.y]=next.turn;
q.push(next);
}
}
}
printf("no\n");
return;
}
int main()
{
int ncase,i,j;
scanf("%d",&ncase);
while(ncase--)
{
scanf("%d %d",&m,&n);
for(i=;i<=m;i++)
for(j=;j<=n;j++)
{
cin>>map[i][j];
turn[i][j]=;//初始化 每一点的转弯个数为一个极大的值
}
cin>>k>>st.y>>st.x>>en.y>>en.x;
bfs();
}
}