迷宫2 ——单调队列解决bfs问题
链接:https://ac.nowcoder.com/acm/problem/15196
来源:牛客网
题目描述
这是一个关于二维格子状迷宫的题目。迷宫的大小为N*M,左上角格子座标为(1,1)、右上角格子座标为(1,M)、左下角格子座标为(N,1)、右下角格子座标为(N,M)。每一格都用-1到109之间的整数表示,意义分别为:-1为墙壁,0为走道,而1到109之间的正整数代表特殊的走道。
蜥蜴最初位于迷宫的座标(1,1)的格子,每一步蜥蜴只能往上、下、左、右、左上、右上、左下、右下八个方向之一前进一格,并且,他也不能走出迷宫边界。蜥蜴的目的地是走到迷宫的右下角格子,也就是座标位置(N,M)。我们想要动一些手脚,使得蜥蜴没有办法从(1,1)出发并抵达(N,M)。我们学会了一个邪恶的法术,这个法术可以把特殊的走道变成墙壁,施法一次的代价为表示该特殊走道的正整数。
假设,我们可以在蜥蜴出发之前不限次数的使用这个邪恶的法术,所花的总代价即为每次施法代价的总和,蜥蜴出发之后就不能再使用这个法术了,请问让蜥蜴没办法达到终点所必须花费的最小总代价是多少呢?
注意,0所代表的走道是无法变为墙壁的。
输入描述
输入的第一行有三个正整数Q,N,M。
代表接下来有Q组数据,这Q组数据都是N*M的迷宫。
接下来每组数据各N行,代表一个迷宫,每行各M个整数,第i行中的第j个整数代表迷宫座标(i,j)的格子。
输出描述
每一组数据输出一行,如果无论如何蜥蜴都能到达终点,请在这一行中输出-1,否则请在这一行中输出一个代表答案的整数。
数据范围
1<=Q<=5*103
1<=Q*N*M<=2.5*105
1<=N,M<=500
代表迷宫格子的数字为介于-1和109间的整数(包含-1和109)
每个迷宫中,代表座标(1,1)和(N,M)的格子的数字一定是0
分析
这道题比较有意思了,大体意思就是我们需要将一些格子堵上,然后图中没有任何路线,所以我们想的是 ,建墙
因为是从左上角前往右下角,所以我们可以从左边墙壁往上面墙壁或者右边墙壁建立围墙,也可以从下面墙壁往上面墙壁或者右边墙壁建立围墙,结合这道题的数据范围可以用有限队列优化一下,写法跟堆优化版的Dijkstra算法有点类似
然后需要注意一下数据范围,需要开到long long这么大,如果过了55%的点的话大概率就是ans开的int范围,如果过了95%的点的话应该就是一开始INF赋值的时候少了,这道题的数据范围差不多到了long long的边界了
代码
#include <queue>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
struct node{
ll d;
int x,y;
friend bool operator < (node a,node b)
{
return a.d > b.d;
}
};
const int N = 510;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll map[N][N];
ll d[N][N];
int n,m,q;
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
int main(){
scanf("%d%d%d",&q,&n,&m);
while(q--){
priority_queue<node> Q;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++){
scanf("%lld",&map[i][j]);
if(map[i][j] == -1) map[i][j] = 0;
else if(map[i][j] == 0) map[i][j] = -1;
d[i][j] = INF;
}
for(int i = 1;i <= n;i++){
if(map[i][1] == -1) continue;
Q.push({map[i][1],i,1});
d[i][1] = map[i][1];
}
for(int i = 1;i <= m;i++){
if(map[n][i] == -1) continue;
Q.push({map[n][i],n,i});
d[n][i] = map[n][i];
}
ll ans = -1;
while(!Q.empty()){
auto t = Q.top();
Q.pop();
if(t.x == 1 || t.y == m){
ans = t.d;
break;
}
for(int i = 0;i < 4;i++){
int a = t.x + dx[i];
int b = t.y + dy[i];
if(a < 1 || a > n || b < 1 || b > m) continue;
if(map[a][b] == -1) continue;
if(d[a][b] > t.d + map[a][b]){
d[a][b] = t.d + map[a][b];
Q.push({d[a][b],a,b});
}
}
}
printf("%lld\n",ans);
}
}