题目描述
Bessie和其他一些人去滑雪。Bessie发现她自己站在一块R*C(1<=R,C<=100)的区域中,区域中的每一块都有一个高度值E_ij(-25<=E_ij<=25)。为了参加大家的聚会,Bessie想要尽快到达右下角。Bessie每一步只能向正东,正西,正南,正北前进一步。Bessie以初速度V(1<=V<=1,000,000)前进,她发现了一个她的速度和高度的关系。当Bessie从高度A移动到高度B时,他的速度就乘上了一个数2^(A-B)。Bessie移动一步的速度取决于她在前一格时的速度。
请找出Bessie移动所需的最小时间。
Input
第1行:3个用空格隔开的整数:V,R,C,分别表示Bessie的初速度和区域的长度和宽度
第2 - R+1行:以矩阵的形式表示该区域中各块的高度。
Output
输出一个实数(保留2位小数),表示Bessie达到目的地最少需要的时间。
Sample Input
1 3 3
1 5 3
6 3 5
2 4 3
Sample Output
29.00
Data Constraint
Hint
【样例说明】
Bessie的最佳路径是:
(1,1) 时间 0 速度 1
(1,2) 时间 1 速度 1/16
(2,2) 时间 17 速度1/4
(3,2) 时间 21 速度1/8
(3,3) 时间 29 速度 1/4
分析
这题我们用记忆化搜索做,然后可以加一点小优化:根据乘除抵消的定理,到某个格子的速度是一个限定的值,所以每个格子的高度减去起始高度再计算出来的速度就是经过这个格子的速度了
然后小数精度尤为恶心,C++无法克服(也许可以减去一个的值达成,但我不知道)
同样的程序,Pascal是可以AC的
这里是错一个点的程序(我真不知道怎么处理这个极小的误差)
#include <fstream>
#include <cstdio>
#include <iomanip>
#include <cmath>
#define eps 0.0000000000551
#define rep(i,a,b) for (i=a;i<=b;i++)
using namespace std;
int r,c,v;
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
struct point
{
int x,y;
long double v;
}state[1000001];
long long by[51];
int d[101][101];
long double f[101][101];
bool pd(int x,int y)
{
if (x<1&&x>r&&y<1&&y>c) return false;
return true;
}
void init()
{
int i,j;
freopen("cowski.in","r",stdin);
scanf("%d%d%d",&v,&r,&c);
rep(i,1,r)
rep(j,1,c)
{
scanf("%d",&d[i][j]);
f[i][j]=2147483647;
}
by[0]=1;
rep(i,1,50)
by[i]=by[i-1]*2;
}
void bfs()
{
int h=0,t=1,i;
state[1].x=1;
state[1].y=1;
state[1].v=v;
f[1][1]=0;
do
{
h++;
rep(i,0,3)
if (pd(state[1].x+dx[i],state[1].y+dy[i]))
{
long double v=state[h].v,s=f[state[h].x][state[h].y];
int x=state[h].x+dx[i],y=state[h].y+dy[i];
if (s+1/v>=f[x][y]) continue;
f[x][y]=s+1/v;
t++;
state[t].x=x;
state[t].y=y;
int h1=d[state[h].x][state[h].y],h2=d[x][y];
if (h1>=h2)
state[t].v=v*by[h1-h2];
else
state[t].v=v/by[h2-h1];
}
}
while (h<t);
}
int main()
{
ofstream fout("cowski.out");
init();
bfs();
fout<<fixed<<setprecision(2)<<abs(f[r][c]-eps);
}