题目大意:
一只小船在水中行走,想要到达目的地,然后有八个方向,用0 …… 7表示,分别是北,东北,东,东南……,而它在任何一点都有一个方向,而当它的下一步走的方向跟它此刻自己的顺风方向相同的时候(即下一步的方向跟它的数字相同),走这一步不需要耗费能量,否则耗费的能量为1个单位能量。然后要求这只小船到达目的地所需的最小能量。
解题思路:
一下来就感觉其实实现的方法比较容易,应该用优先队列的,只是那个状态标志要稍微变一下,走过的点不能简简单单地用visited[],因为由一个点扩张出去,有可能下个点也要走上个点扩张出去的点。因为当前点走到下一个点(即上一个点的扩张出去的点)消耗的能量比上一次的要小,所以要用另一个vst[]来标志这个点已被走过的能量值。只要下一次到达该点的能量值能够小于这个点,那么就可以入队。(注意每个点是可以走多次的,想清楚状态很重要)
#include<stdio.h>
#include<string.h>
#include<queue>
int dir[8][2]={{-1,0},{-1,1},{0,1},{1,1},
{1,0},{1,-1},{0,-1},{-1,-1}};这八个方向是有顺序的。。
char map[2100][2100];
int vst[2100][2100];
using namespace std;
int n,m;
struct point
{
int x,y;
int time ;
friend bool operator<(const point &a,const point &b)//为何后面的这种写法就超时呢,希望大牛解释 friend bool operator<(point a,point b)
{
return a.time>b.time;
}
};
int judge(int x,int y)
{
return x>=1&&x<=n&&y>=1&&y<=m;
}
int bfs(int x0,int y0,int x1,int y1)
{
int i,j,dx,dy;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
vst[i][j]=999999;
priority_queue<point>q;
point in,out;
in.x=x0;
in.y=y0;
in.time=0;
vst[x0][y0]=0;
q.push(in);
while(!q.empty())
{
out=q.top();
q.pop();
if((out.x==x1)&&(out.y==y1))
return out.time;
for(i=0;i<8;i++)
{
dx=in.x=out.x+dir[i][0];
dy=in.y=out.y+dir[i][1];
if(!judge(dx,dy))
continue;
if(i==(map[out.x][out.y]-'0'))
in.time=out.time;
else
in.time=out.time+1;
if(in.time<vst[dx][dy])
{
vst[dx][dy]=in.time;
q.push(in);
}
}
}
return 0;
}
int main()
{
int i,j,k,h;
int ex,ey,sx,sy;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n;i++)
{
scanf("%s",map[i]+1);
}
scanf("%d",&k);
while(k--)
{
scanf("%d%d%d%d",&ex,&ey,&sx,&sy);
printf("%d\n",bfs(ex,ey,sx,sy));
}
}
return 0;
}