CSUOJ 你经历过绝望吗?两次!【二分+bfs】

CSUOJ 你经历过绝望吗?两次!


题目大意:

  • 一个迷宫,要求走到迷宫边缘
  • 有不能走的墙壁,不需要花费的通道和需要 1 点花费的通道
  • 问最少需要多少花费才能走出迷宫,不能走出输出 -1

解题过程:

  • 二分确定费用最小值,O(log NM)
  • 想到用bfs来找路径,然后用优先队列优化bfs(类似优先队列优化dijkstra那样), 类似di’jkstra,复杂度为 O(NM logNM)
  • 总复杂度 O(NM log^2 NM)

AC代码:

#include<iostream>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
#define rep(i,l,p) for(int i=l;i<=p;i++)
#define fread() freopen("in.txt","r",stdin);
const int dx[4] = {0,0,1,-1},dy[4] = {1,-1,0,0};
char s[105];
int Map[105][105];
int v[105][105];
int d[105][105];
int n,m,T;
struct Node
{
    int x,y,d;
    bool operator<(const Node &b)const{
        return d < b.d;
    }
}beg;
priority_queue<Node> q;
void init(){
    while(!q.empty()) q.pop();
    memset(v,0,sizeof v);
    memset(d,0x3f,sizeof d);
}
void input(){
    memset(Map,0,sizeof Map);
    cin >> n >> m;
    rep(i,1,n){
        cin >> s;
        int len = strlen(s);
        rep(j,0,len-1){
            if(s[j] == '#') Map[i][j+1] = 0x3f3f3f3f;
            else if(s[j] == '.') Map[i][j+1] = 0;
            else if(s[j] == '*') Map[i][j+1] = 1;
            else if(s[j] == '@') {
                Map[i][j+1] = 0;
                beg.x = i; beg.y = j+1; beg.d = 0;
            }
        }
    }
    // if(T==2){
    //  rep(i,1,n){
    //      rep(j,1,m) cout << Map[i][j] << " ";
    //      cout << endl;
    //  }
    // }
}
bool solve(int mid){
    q.push(beg);
    v[beg.x][beg.y] = 1;
    d[beg.x][beg.y] = 0;
    while(!q.empty()){
        Node now = q.top(); q.pop();
        int x = now.x,y = now.y;
        // if(v[now.x][now.y]) continue;
        // if(now.d > mid) continue;
        int tx,ty,i;
        for(i=0;i<4;i++){
            tx = dx[i]+now.x; ty = dy[i] + now.y;
            if(tx < 1 || tx > n || ty < 1 || ty > m) return true;
            int len =Map[tx][ty]+d[x][y];
            if(len <= mid && len < d[tx][ty]){
                d[tx][ty] = len;
                if(!v[tx][ty]) q.push({tx,ty,-d[tx][ty]}),v[tx][ty] = 1;
            }
        }
    }
    return false;
}
int main(int argc, char const *argv[])
{
    // fread();
    ios::sync_with_stdio(false);
    cin >> T;
    while(T--){
        init();
        input();
        int l = 0,r = n*m+1;
        int mid;
        while(r > l){
            init();
            mid = (r+l)>>1;
            // if(T == 2) cout << mid << endl;
            if(solve(mid)){
                r = mid;
                // if(T==2)cout << " ans :" << mid << endl;
            }else {
                l = mid +1;
            }
        }
        if(l == n*m+1){
            cout << -1 << endl;
        }else cout << l << endl;

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Hagtaril/article/details/80603501