思路分析
这显然是一个01BFS,根据其性质我们只需要将消耗为0的点放在前面,消耗为1的放在后面再一个一个遍历即可。然后不断更新当前点消耗能量的最小值,待遍历结束后输出ans[tx][ty]即可。这里用queue是不行的,需要使用优先队列来实现上述功能。
注意:不能用vis来标记某个点是否被访问过,因为有可能第一遍被访问的时候并不是最优的解
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#define xx tmp.x
#define yy tmp.y
#define pp tmp.power
#include <queue>
using namespace std;
char map[1002][1002];
int ans[1002][1002];
int step[8][2]=
{
-1,0,
-1,1,
0,1,
1,1,
1,0,
1,-1,
0,-1,
-1,-1
};
int n,m;
int sx,sy,tx,ty;
int que;
struct point
{
int x,y,power;
bool operator < (const point &a) const
{
return power>a.power;//最小值优先
}
};
priority_queue<point> q;
bool inmap(int x,int y){return x>0 && y>0 && x<=n && y<=m;}
void bfs()
{
register int i,j;
int nx,ny,nt;
memset(ans,0x7f,sizeof(ans));
q = priority_queue<point>();
ans[sx][sy] = 0;//显然
q.push((point){sx,sy,0});
while(!q.empty())
{
point tmp = q.top();
q.pop();
for(i=0;i<8;i++)
{
nx = xx + step[i][0];
ny = yy + step[i][1];
nt = pp + (i != map[xx-1][yy-1]-'0');//巧妙的写法
if(nt < ans[tx][ty] && nt < ans[nx][ny] && inmap(nx,ny))//你目前消耗的能量都超过当前最优解了还算个鸡
{
if(nx != tx || ny != ty)
q.push((point) {nx,ny,nt});
ans[nx][ny] = nt;
}
}
}
printf("%d\n",ans[tx][ty]);
}
int main()
{
register int i,j;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=0;i<n;i++)cin>>map[i];
scanf("%d",&que);
for(i=1;i<=que;i++)
{
scanf("%d%d%d%d",&sx,&sy,&tx,&ty);
if(sx==tx && sy==ty){printf("0\n");continue;}
bfs();
}
}
return 0;
}