AT164 暗闇帰り道(二分+bfs)
这道题的正解是二分 + bfs,然而我用 spfa 水过了。
题目要求一条从起点到终点的路径,使得其最小亮度最大并输出它。在 \(k\) 时间到达格子 \(c_{i,j}\) 时,这个格子的亮度是 \(c_{i,j}\times 0.99^k\)。
单源最短路的本质是贪心,思路是反向跑最短路,则设 \(d_x\) 为从终点到 \(x\) 的最大化的最小亮度,\(d_v=\min(d_u\times 0.99,c_v)\)。反向保证了“最大”。
迪杰斯特拉、spfa 均能通过。正向跑最短路需要额外记录步数,但也能通过(注意细节)。
下面是 AC 代码:
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef double db;
typedef pair<int,int> pii;
const int dx[5]={0,0,0,1,-1};
const int dy[5]={0,1,-1,0,0};
queue<pii> q;
int n,m,a[505][505];
char b[505];
db ans[505][505],eps=1e-10;
int main(){
int sx,sy,tx,ty;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%s",b+1);
for(int j=1;j<=m;++j)
if(b[j]=='s') sx=i,sy=j,a[i][j]=10;
else if(b[j]=='g') tx=i,ty=j,a[i][j]=10;
else if(b[j]=='#') a[i][j]=-1;
else a[i][j]=(b[j]^48);
}
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) ans[i][j]=-1;
q.push({tx,ty}),ans[tx][ty]=10;
while(!q.empty()){
pii u=q.front();q.pop();
for(int i=1;i<=4;++i){
pii v={u.x+dx[i],u.y+dy[i]};
if(v.x<1||v.x>n||v.y<1||v.y>m||a[v.x][v.y]==-1) continue;
if(min(ans[u.x][u.y]*0.99,(db)a[v.x][v.y])-ans[v.x][v.y]>eps){
ans[v.x][v.y]=min(ans[u.x][u.y]*0.99,(db)(a[v.x][v.y]));
q.push(v);
}
}
}
if(ans[sx][sy]==-1) puts("-1");
else printf("%.10lf\n",ans[sx][sy]);
return 0;
}