天天看點

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

題意分析:一個有坡度的滑雪場,每次移動, 速度v的變化v=v*2^(移動前坡度-移動後坡度),求從左上角到右下角最短時間是多少。

思路:這顯然是一個最短路問題,隻不過需要轉化一下。對于一個确定的r*c的矩陣,因為初速度V已給出,是以矩陣上的任意一點的速度都已确定,即每一點到其相鄰的點的時間已知。

有兩種方法。

【1】SPFA算法

附上代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
const double Max=1e10;
int v,r,c;
int aa[105][105];
double dv[105][105], dis[105][105];
int cun[4][2]={{1,0},{0,1},{0,-1},{-1,0}};
struct node{
	int x,y;//用x,y來表示一個點 
};
void SPFA()
{
	int mp[105][105];//用來标記進入隊列的點 
	int i,j,k,l;
	for(i=0;i<=r;i++)
	{
		for(j=0;j<=c;j++)
		{
			dis[i][j]=Max;
			mp[i][j]=0;
		}
	}
	queue<node> p;
	node q,t;
	q.x =1;q.y =1;
	mp[1][1]=1;
	dis[1][1]=0;
	p.push(q);
	while(p.size())
	{
		q=p.front() ;
		p.pop() ;
		mp[q.x ][q.y ]=0;
		for(i=0;i<4;i++)
		{
			j=q.x +cun[i][0];
			k=q.y +cun[i][1];
			if(j<0||j>r||k<0||k>c)continue;
			if(dis[j][k]>(1/dv[q.x ][q.y ]+dis[q.x ][q.y ]))
			{
				dis[j][k]=1/dv[q.x ][q.y ]+dis[q.x ][q.y ];
				if(mp[j][k]==0)
				{
					t.x =j;t.y=k;
					mp[j][k]=1;
					p.push(t); 
				}
			}
		}
	}
	
}
int main()
{
	scanf("%d%d%d",&v,&r,&c);
	int i,j,k;
	for(i=1;i<=r;i++)
	{
		for(j=1;j<=c;j++)
		{
			scanf("%d",&aa[i][j]);
		}
	}
	for(i=1;i<=r;i++)
	{
		for(j=1;j<=c;j++)
		{
			dv[i][j]=v*pow(2.0,(double)(aa[1][1]-aa[i][j]));//計算每一點的速度。 
		}
	}
	SPFA(); 
	printf("%.2lf",dis[r][c]);
    return 0;
}//c++送出AC,G++過不了,還望大佬指導
           

【2】Dijkstra算法

附上代碼:

#include<stdio.h> 
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const double INF = 0x7fffffff;
struct node {
	ll id;
	double d;
	ll next_s;
}side[50000];

ll head[10001],cn;

void init(){
	memset(head,-1,sizeof(head));
	cn=0;
}
void add(ll x,ll y,double z){
	side[cn].id=y;
	side[cn].d=z;
	side[cn].next_s=head[x];
	head[x]=cn++;
}
double dis[10001];
ll flag[10001]; 
double h[101][101];
double V[101][101];
int main(){
	ll v,r,c;
	cin>>v>>r>>c;
	for(int i=1;i<=r;i++){
		for(int j=1;j<=c;j++){
			 cin>>h[i][j];
		}
	}
	
	ll cnt=0;
	V[1][1]=v*1.0;
	for(int i=1;i<=r;i++){
		for(int j=1;j<=c;j++){
			V[i][j]=V[1][1]*pow(2.0,(double)(h[1][1]-h[i][j]));
		}
	}
	init();
	for(int i=1;i<=r;i++){
		for(int j=1;j<=c;j++){
			cnt++;//将每個點從1~r*c進行依次标記
			if(j+1<=c){//存圖,記錄兩個相鄰點間的時間,雙向 
				add(cnt,cnt+1,1.0/V[i][j]);
				add(cnt+1,cnt,1.0/V[i][j+1]);
			}
			if(i+1<=r){
				add(cnt,cnt+c,1.0/V[i][j]);
				add(cnt+c,cnt,1.0/V[i+1][j]);
			}
		}
	}
	for(int i=1;i<=cnt;i++){
		dis[i]=INF;
	}
	dis[1]=0;
	flag[1]=1;
	queue<ll> p;
	p.push(1);
	while(!p.empty()){
		ll index=p.front();
		p.pop();
		flag[index]=0;
		for(int i=head[index];i!=-1;i=side[i].next_s){
			if(dis[side[i].id]>dis[index]+side[i].d){
				dis[side[i].id]=dis[index]+side[i].d;
			
			if(!flag[side[i].id]){
				p.push(side[i].id);
				flag[side[i].id]=1;
			}    }
		}
	}

	printf("%.2f\n",dis[cnt]);
	return 0;
}
           

繼續閱讀