[DP][BFS]滑雪

这是一篇关于滑雪问题的解析,Bessie需要在R*C的网格中找到最快到达右下角的路径。每一步只能向四个方向移动,速度会受高度变化影响。通过记忆化搜索和高度差计算速度,寻找最优路径。样例输入输出和数据约束也给出,但C++处理小数精度问题存在困难。
摘要由CSDN通过智能技术生成

题目描述
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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值