解题思路:对优先队列有了更深的理解。以前写优先队列是针对那种有权的最短路问题,搜出来的必定是道路的花费最优解,我们可以用book标记走过的地方,下次不必要再走;而本题由于用了优先队列,走过的点到底要不要再考虑呢?假设上次到达本点拐弯了1次,而现在却拐弯了2次,当然不要本次的这个方法走,相反如果本次用1次,而上次用2次,就要用本次的方法。如果两次的拐弯数一致呢?其实两种都要搜,为什么?因为你进来的方向一定是不同的,而之后你这个方向直直下去如果有终点,你的最小拐弯就是到达本点这么多了,而另外一种方向还要再拐弯一次!

AC代码如下:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#define inf 0x3f3f3f3f
using namespace std;

struct node
{
	int x,y,k,bearing;
	friend bool operator < (node a,node b)
	{
		return a.k>b.k;
	}
};

char image[110][110];
int n,m,tx,ty,k,nex[4][2]={0,1,1,0,0,-1,-1,0},book[110][110];
priority_queue<node> Q;

bool judge(int x,int y)
{
	if(x<1||x>n||y<1||y>m||image[x][y]=='*')
		return true;
	return false;
}

bool bfs(int x,int y)
{
	if(x==tx && y==ty)
		return true;
	int i;
	node now,xia;
	while(!Q.empty())
		Q.pop();
	book[x][y]=0;
	for(i=0;i<4;i++)
	{
		xia.x=x+nex[i][0];
		xia.y=y+nex[i][1];
		if(judge(xia.x,xia.y))
			continue;
		xia.k=0;
		xia.bearing=i;
		book[x][y]=0;
		Q.push(xia);
	}
	while(!Q.empty())
	{
		now=Q.top();
		Q.pop();
		if(now.x==tx && now.y==ty)
			 	return true;
		for(i=0;i<4;i++)
		{
			xia.x=now.x+nex[i][0];
			xia.y=now.y+nex[i][1];
			if(judge(xia.x,xia.y))
				continue;
			xia.k=now.k;
			xia.bearing=i;
			if(xia.bearing!=now.bearing)
				xia.k++;
			if(xia.k>k || book[xia.x][xia.y]<xia.k)  //注意,这里的剪枝当拐弯的次数等同于上一次走过这里的时候不能去掉,因为本次到达这里由于进来的方向不同,能到达的终点也许不同
				continue;
			if(xia.x==tx && xia.y==ty)
			 	return true;
			book[xia.x][xia.y]=xia.k;
			Q.push(xia);
		}
	}
	return false;
}

int main()
{
	int i,j,t,x,y;
	cin>>t;
	while(t--)
	{
		cin>>n>>m;
		getchar();
		for(i=1;i<=n;i++)
		{
			cin>>image[i]+1;
			for(j=1;j<=m;j++)
				book[i][j]=inf;
		}
		cin>>k>>y>>x>>ty>>tx;
		if(bfs(x,y))
			cout<<"yes"<<endl;
		else
			cout<<"no"<<endl;
	}
	return 0;
}

测试数据:

1
5 5
*....
..*..
.*..*
*....
*....
2 3 5 5 2