题目大意:
- 一个迷宫,要求走到迷宫边缘
- 有不能走的墙壁,不需要花费的通道和需要 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;
}
}
}
}
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;
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[])
{
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(solve(mid)){
r = mid;
}else {
l = mid +1;
}
}
if(l == n*m+1){
cout << -1 << endl;
}else cout << l << endl;
}
return 0;
}