题目链接:洋流 (nowcoder.com)
本题才是用BFS进行求解,但是单纯的使用BFS会出现错误,因为并不是每一步都是相同的消耗,如果让消耗多的先进入了那么该点就不是最小的消耗。可以使用一个优先队列来维护,每次都让最小的消耗去走,这样可以保持没一点都是由最小的来进入。
但在本题当中,由于是01之间的消耗。所以可以使用一个双端队列,如果是0的消耗就放入对头,如果是1的消耗就放到队尾这样就保持队首一直是小的。
在这里面到达某一个坐标的消耗用一个二维数组保存,并且要在队列头拿出来的时候进行判断不然会出现错误。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000+1;
struct Node {
int x, y;
};
int a[maxn][maxn];
int n, m;
int begin_x, begin_y;
int end_x, end_y;
int ans = 0;
// map<pair<int, int>, int> fd;
int vis[maxn][maxn];
deque<Node> pq;
int mv[8][2] {
{-1,0},//北
{-1,1},//东北
{0,1},//东
{1,1},//东南
{1,0},//南
{1,-1},//西南
{0,-1},//西
{-1,-1}//西北
};
void BFS() {
vis[begin_x][begin_y] = 0;
pq.push_front({begin_x, begin_y});
while (pq.size()) {
Node p = pq.front();
int x=p.x;int y=p.y;
pq.pop_front();
if (x==end_x&&y==end_y) {
return ;
}
//进行移动,移动过程中判断是否消耗体力
for (int i=0;i<8;i++) {
int next_x = x+mv[i][0];
int next_y = y+mv[i][1];
if (next_x<=0||next_x>n||next_y<=0||next_y>m) continue;
if (a[x][y]==i){
if (vis[next_x][next_y]<=vis[x][y]) continue;
}
else if (vis[next_x][next_y]<=vis[x][y]+1) continue;
if (a[x][y]==i) {
pq.push_front({next_x, next_y});
vis[next_x][next_y] = vis[x][y];
// fd[{next_x, next_y}] = val;
}else {
pq.push_back({next_x, next_y});
vis[next_x][next_y] = vis[x][y]+1;
// fd[{next_x, next_y}] = val+1;
}
}
}
}
int main() {
cin>>n>>m;
for (int i=1;i<=n;i++) {
for (int j=1;j<=m;j++) {
scanf("%1d", &a[i][j]);
}
}
int T;
cin>>T;
while (T--) {
memset(vis, 0x3f, sizeof(vis));
ans = 0;
while (!pq.empty()) pq.pop_back();
cin>>begin_x>>begin_y;
cin>>end_x>>end_y;
BFS();
cout<<vis[end_x][end_y]<<endl;
}
return 0;
}