广搜优化-洋流

题目链接:洋流 (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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值