一、Dijskstra算法

     参考我之前一篇博文:http://www.cnblogs.com/Oloo/articles/3614810.html

     或者《算法导论》第24章单源最短路 Dijskstra算法部分

 二、问题描述

     POJ 2253http://poj.org/problem?id=2253

     一共有两只青蛙,分别位于湖中两块不同的石头上,一只青蛙想要跳到另一只青蛙那里,通过湖中的石头。现在给出湖中石头的坐标,要求青蛙至少每次能跳多远,才能顺利到达另一只青蛙那里。

 三、问题分析

     编程之前需要解决三个问题:

     问题一、图的构造?

     问题二、单源最短路or每对顶点间最短路 / BellmanFord or Dijskstra

     问题三、如何修改Dijskstra算法?

   

     问题一:这道题目图的构造还是不算难的!以每块石头为节点,任意两块石头之间都有边,边的权重可以根据这两块石头的坐标来计算,这样图就构造出来了。

     

     问题二:我们要求青蛙至少要具备的最少的跳跃距离。

     首先,我考虑,这个题目还是给出了起点和终点,即两只青蛙的坐标。所以还是考虑单源最短路的相关算法通过修改来解决这个问题。

     因为每条边的权重肯定是正的,即不存在负权边,所以,立马考虑使用Dijskstra算法来做。

     

     问题三:通过考虑给出的第二个样例,我发现要求的值并不在最短路径上,所以,这个问题不是个求最短的问题。所以,就可以立马想到修改Dijskstra算法的Relax的条件,即什么时候要修改目标节点vD值?通过观察,我找到了这样的规则,在松弛u邻接节点v的时候,如果D[v] > D[u] && D[v] > W[u,v],那么这时候就需要进行修改D[v],将D[v] = max{D[u],W[u,v]},至此,这道题就可以说解决了。

 四、程序实现

 1 #include<iostream>
 2 #include<iomanip>
 3 #include<cmath>
 4 using namespace std;
 5 #define INF 1000000000
 6 struct stone
 7 {
 8     int x,y;
 9 } *stones;
10 int N;//石头数目
11 int *value;//顶点D值
12 int *flag;
13 int edges[202][202];
14 
15 void input()
16 {
17     value = new int[N];
18     flag = new int[N];
19     for(int i = 0;i < N;i++)
20     {
21         value[i] = INF;
22         flag[i] = 1;
23     }
24     value[0] = 0;
25 
26     stones = new stone[N];
27     for(int i = 0;i < N;i++)
28         cin >> stones[i].x >> stones[i].y;
29 
30     for(int i = 0;i < N;i++)
31         for(int j = 0;j < N;j++)
32         {
33             edges[i][j] = (stones[j].x - stones[i].x)*(stones[j].x - stones[i].x) 
34                 + (stones[j].y - stones[i].y)*(stones[j].y - stones[i].y);
35         }
36 }
37 
38 int ExtractMin()
39 {
40     int min = INF; int index = -1;
41     for(int i = 0;i < N;i++)
42     {
43         if(min > value[i] && flag[i])
44         {
45             min = value[i];
46             index = i;
47         }
48     }
49     return index;
50 }
51 
52 int Mmax(int a ,int b)
53 {
54     if(a > b) return a;
55     else return b;
56 }
57 
58 void Relax(int u , int v)
59 {
60     if(value[v] > edges[u][v] && value[v] > value[u])
61     {
62         value[v] = Mmax(edges[u][v],value[u]);
63     }
64 }
65 
66 void Dijskstra()
67 {
68     int k = 0;
69     while(k != N)
70     {
71         int u = ExtractMin();
72         if(flag[u])
73         {
74             flag[u] = 0;
75             for(int v = 0;v < N;v++)
76                 Relax(u , v);
77         }
78         k++;
79     }
80 }
81 
82 int main()
83 {
84     int t = 1;
85     while(cin >> N)
86     {
87         if(N == 0) break;
88         input();
89         Dijskstra();
90         cout<<setiosflags(ios::fixed);
91         cout <<"Scenario #"<<t<<endl;
92         cout <<"Frog Distance = "<< setprecision(3)<< sqrt((double)(value[1])) << endl;
93         cout << endl;
94         t++;
95     }
96     return 0;
97 }
View Code

 四、出现问题

     问题1——精度问题:

     这个题目要求保留三位小数,在这里赘述一下C++cout怎么设置保留精度<还是cprintf用着舒服>,需要的代码如下:

 

1 #include<iomanip>
2 
3 cout<<setiosflags(ios::fixed);
4 
5 setprecision(3)
View Code

 

     问题2——POJ 编译问题

     这道题,第一次交的时候,以为一次就可以AC呢,结果CE了,看了编译信息发现,原来没有包含cmath头文件,就直接使用了sqrt(),不知道为什么我的VS 2012没报错。。

这里包含了文件cmath之后,其实还有问题,那就是sqrt这个函数被重载过的,所以要指明想要调用哪一个函数,即sqrt((double)parameter),指明就可以,这种会在传入int型参数的时候出现。

 五、感想

       自己通过自己独立分析问题,自己独立编程实现,最后这个题目AC,这个节奏还是很好的~

       最后,YZY,我想你!

 

 

 

 

 

posted on 2014-03-23 12:53  Oloo  阅读(240)  评论(0)    收藏  举报