Skiing(最短路)

时间:2022-09-11 05:54:33
                            poj——3037 Skiing
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 4921   Accepted: 1315   Special Judge

Description

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
中文翻译:

滑雪
时间限制:1000MS内存限制:65536k
总提交:4921接受:1315特别法官
描述
Bessie和其他农场主约翰的母牛今年冬天要去滑雪。有一天,贝西发现自己在左上角的R(1 25 = R = = 100)由C(1 = C = C =)网格海拔E(-电子= 25)。为了加入FJ在discow党的其他牛,她必须到右下角,很快她可以通过旅行只有北,南,东,西。
Bessie以初始速度V开始旅行(1 < V = V = 1000000)。她发现她的速度和海拔变化之间有着显著的关系。当Bessie从一个高度位置八B相邻的位置,她的速度乘以2号^(A-B)。Bessie从一个地点到另一个地点旅行的时间是她在第一个位置时速度的倒数。
找到两个最小的时间将采取贝茜加入她的牛朋友。
输入
*第1行:三个空间分离的整数:V,R和C,分别代表Bessie的初始速度和网格中的行和列的数目。
*行2 + R + 1:C整数表示网格上的相应位置的海拔E。
输出
一个单数值,打印到两个完全小数的位置:Bessie可以到达网格右下角的最小时间。
样本输入
1 3 3
1 5 3
6 3 5
2 4 3
示例输出
二十九
提示
Bessie的最佳路线是:
开始时1时0速度1
东到1,2时间1速度1 / 16
南至2时间17速度1 / 4
南至3,2时间21速度1 / 8
东3时间29速度1 / 4

usaco 2005十月黄金

思路:
Skiing(最短路)
题意:你在一个R*C网格的左上角,现在问你从左上角走到右下角需要的最少时间.其中网格中的任意两点的时间花费可以计算出来.
思路:

首先我们需要证明的是从左上角出发到R*C网格中其他任意一点的速度都是固定的.对于下面的矩阵:

1 5 3

6 3 5

2 4 3

我们想计算到数值为6的点时的速度? 从1->6的话 v6=v1*2^(1-6)

而从1->5 5->3 3->6 的话 v6=v1*2^(1-5) * 2^(5-3) * 2^(3-6)=v1*2^(1-6)

相等,同理我们可以证明到任意点的速度为:

 v(i,j)= v1*2^(1号点与该点的海拔之差)

       既然任意点的速度都是固定的,那么从该点到它的4个方向的边的时间开销也是固定的.

直接建立该无向图,计算出对应每条边的时间开销,然后用最短路算法计算从0号节点到R*C-1点的最短距离(时间开销)即可.

过程中注意将该网格转换为一个节点编号的无向图的方法.

注意:这个题要使用队列优化,否则会超时!!!开大极大值,不然老wa
代码:
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 105
#define maxn 9000000000//妈的,极大值开小了,卡了我一个多小时!交了6遍一直wa
using namespace std;
int n,m,v,a[N][N];
double dis[N][N];
bool vis[N][N];
]={-,,,},y[]={,,,-};
struct Node
{
    int x,y;
    double t,v;
    Node (int x,int y,double t,double v)
    {
        this->x=x;
        this->y=y;
        this->t=t;
        this->v=v;
    }//结构体的初始化,只能在第一次调用结构体的时候使用
    friend bool operator < (Node a,Node b)
    {
        if(a.t==b.t)
         return a.v<b.v;
        return a.t>b.t;
    }// operator重载运算符,只要调用到该结构体,就会按照结构体中重新定义的<进行操作。
};
void dijsktra()
{
    priority_queue<Node> q;
    q.push(Node(,,,v));
    while(!q.empty())
    {
        Node p=q.top();
        q.pop();
        if(vis[p.x][p.y]) continue;
        vis[p.x][p.y]=;
        ;i<;i++)
        {
            int xx=p.x+x[i];//向四个方向扩展该店的路径 ,可看成横坐标。
            int yy=p.y+y[i];//向四个方向扩展该点的路径,可看成纵坐标。
            ||xx>n||yy<||yy>m) continue;//若要扩展的点超出了这个网格的范围,略过。
            if(vis[xx][yy]) continue;//若该点已经访问过,略过。
            if(dis[xx][yy]>p.t+1.0/p.v)//求最短路!term.t原就消耗的时间,1.0/term.v 到该点的时间。
            {
                dis[xx][yy]=p.t+1.0/p.v;
                q.push(Node(xx,yy,dis[xx][yy],p.v*pow(2.0,a[p.x][p.y]-a[xx][yy])));
                 //继续扩展
            }
        }
    }
}
int main()
{
    while(scanf("%d%d%d",&v,&n,&m)!=EOF)//有好几组数据!!
    {
        ;i<=n;i++)
          ;j<=m;j++)
          {
              scanf("%d",&a[i][j]);
              dis[i][j]=maxn;//初始化,边放数边初始,比起先两个for循环初始较快
          }
        memset(vis,,sizeof(vis));
        dis[][]=;//由于是从四方格的最左上角开始走,那样到该点的时间一定是0;
        dijsktra();
        printf("%.2f\n",dis[n][m]);//到达最后右下角所用的时间。
    }
    ;
}