zoukankan      html  css  js  c++  java
  • POJ 3037 Skiing(如何使用SPFA求解二维最短路问题)

    题目链接:

    https://cn.vjudge.net/problem/POJ-3037

    Bessie and the rest of Farmer John's cows are taking a trip this winter to go skiing. One day Bessie finds herself at the top left corner of an R (1 <= R <= 100) by C (1 <= C <= 100) grid of elevations E (-25 <= E <= 25). In order to join FJ and the other cows at a discow party, she must get down to the bottom right corner as quickly as she can by travelling only north, south, east, and west.

    Bessie starts out travelling at a initial speed V (1 <= V <= 1,000,000). She has discovered a remarkable relationship between her speed and her elevation change. When Bessie moves from a location of height A to an adjacent location of eight B, her speed is multiplied by the number 2^(A-B). The time it takes Bessie to travel from a location to an adjacent location is the reciprocal of her speed when she is at the first location.

    Find the both smallest amount of time it will take Bessie to join her cow friends.
    Input
    * Line 1: Three space-separated integers: V, R, and C, which respectively represent Bessie's initial velocity and the number of rows and columns in the grid.

    * Lines 2..R+1: C integers representing the elevation E of the corresponding location on the grid.
    Output
    A single number value, printed to two exactly decimal places: the minimum amount of time that Bessie can take to reach the bottom right corner of the grid.
    Sample Input
    1 3 3
    1 5 3
    6 3 5
    2 4 3
    Sample Output
    29.00
    Hint
    Bessie's best route is:
    Start at 1,1 time 0 speed 1
    East to 1,2 time 1 speed 1/16
    South to 2,2 time 17 speed 1/4
    South to 3,2 time 21 speed 1/8
    East to 3,3 time 29 speed 1/4
     1 /*
     2 题意描述
     3 第一行输入(1,1)处的初始速度v,和高度矩阵的大小r,c 
     4 接下来输入一个高度矩阵
     5 问从(1,1)处出发,走到(r,c)所需要的最短时间
     6 时间的计算规则是,从A点到B点,假设高度是HA,HB,到达B点的速度是A点的速度乘以2^(HA-HB),而该过程所需要的时间是到达B点度的倒数
     7 
     8 解题思路
     9 读完题感觉像是搜索题的最短路,由于花费时间不同,导致同层拓展的结点优先级不同,再采用优先队列保证每次弹出的是最短时间结点,求
    10 出最短时间,有点模拟的意思。
    11 不过仔细读题发现,其实不用像模拟那样随时更新速度,因为只要有了(1,1)点的速度,其他点的速度都能求出来。假设a,b,c三点的高度 
    12 分别是h1,h2,h3, a点的速度为v1,求v2和v3。易得v2=v1*2^(h1-h2);将v2代入v3=v2*2(h2-h3)=v1*2^(h1-h2)*2(h2-h3)=v1*2(h1-h3);故有
    13 有了初始速度其他点的速度是固定的,那么可以将其看成是一个邻接矩阵,求(1,1)到(r,c)的最短路径,权值就是每条边花费的时间。 
    14 这里使用SPFA,
    15                 1.初始化二维数组t为最短路径的估计值,除了(1,1)外,全部都是INF
    16                 在这里需要注意的是,因为是浮点数造成之前的int最大值不适用了,要变为原来的二倍 
    17                 2.在队列中加入一个起始顶点
    18                 每次弹出一个顶点,以该点为中心,四周的最短距离如果能够被该点松弛,就更新。
    19                 如果四周的点没有被用过,就加入队列 
    20                 3.最终队列为空的时候,计算出从(1,1)处出发,走到(r,c)所需要的最短时间。
    21                 POJ精度问题使用%.2f输出,用%.2lf精度太小,舍入不正确 
    22 */
    23 #include<cstdio>
    24 #include<cstring>
    25 #include<queue>
    26 #include<cmath>
    27 using namespace std;
    28 
    29 const double INF = 0x7fffffff;//double是int的二倍,故0x3f3f3f3f的二倍 
    30 const int maxn = 110;
    31 int dir[4][2] = {1,0, 0,1, -1,0, 0,-1};
    32 struct NODE{
    33     int x, y;
    34 };
    35 bool vis[maxn][maxn];
    36 double e[maxn][maxn];
    37 double t[maxn][maxn];
    38 double v; 
    39 int r, c;
    40 void SPFA();
    41 
    42 int main()
    43 {
    44     while(scanf("%lf%d%d", &v, &r, &c) != EOF) {
    45         for(int i = 1; i <= r; i++) {
    46             for(int j = 1; j <= c; j++) {
    47                 scanf("%lf", &e[i][j]);
    48             } 
    49         } 
    50         SPFA();
    51     }
    52     return 0;
    53 } 
    54 
    55 void SPFA() {
    56     for(int i = 1; i <= r; i++) {
    57         for(int j = 1; j <= c; j++) {
    58             t[i][j] = INF;
    59         }
    60     }
    61     t[1][1] = 0;
    62     
    63     memset(vis, 0, sizeof(vis));
    64     vis[1][1] = 1;
    65     queue<NODE> q;
    66     q.push((NODE){1,1});
    67     while(!q.empty()) {
    68         NODE tmp = q.front();
    69         q.pop();
    70         vis[tmp.x][tmp.y] = 0;//清除标记 
    71         double w = 1.0 / (v * pow(2.0, e[1][1] - e[tmp.x][tmp.y]));
    72         for(int k = 0; k < 4; k++) {
    73             int tx = tmp.x + dir[k][0];
    74             int ty = tmp.y + dir[k][1];
    75             
    76             if(tx < 1 || tx > r || ty < 1 || ty > c)
    77                 continue;
    78             if(t[tmp.x][tmp.y] < INF && t[tx][ty] > t[tmp.x][tmp.y] + w) {
    79                 t[tx][ty] = t[tmp.x][tmp.y] + w;
    80                 if(!vis[tx][ty]) {
    81                     vis[tx][ty] = 1;
    82                     q.push((NODE){tx,ty});
    83                 }
    84             }
    85         }
    86     }
    87     
    88     printf("%.2f
    ", t[r][c]);
    89 }
  • 相关阅读:
    4星|《激荡十年,水大鱼大》:过去十年间国内商业简史
    4星|《三联生活周刊》2017年47期:所谓“嬉皮精神”,说白了就是让每一个人都能在不影响其他人的前提下,过自己想要的生活
    3星|《三联生活周刊》2017年48期:联大外文系主任叶公超让学生念一句英语就能判断出学生的籍贯
    3星|《终身成长》:成长型思维让人进步,固定型思维让人固步自封。有新意的励志书,但有锤子模式的嫌疑。
    4星|《癌症新知:科学终结恐慌》:非常新鲜的癌症科普
    PL/SQL Developer使用技巧
    Oracle数据导入导出imp/exp sp2-0734:未知的命令开头'imp...解决方法
    oracle数据库导入导出命令!
    如何完全卸载VS2010
    Oracle命令(一):Oracle登录命令
  • 原文地址:https://www.cnblogs.com/wenzhixin/p/9383135.html
Copyright © 2011-2022 走看看