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;
}

THE END

posted @ 2021-08-25 21:07  q0000000  阅读(55)  评论(0编辑  收藏  举报