码迷,mamicode.com
首页 > 编程语言 > 详细

Dijkstra算法(求解单源最短路)详解 + 变形 之 poj 1860 Currency Exchange

时间:2015-12-08 23:55:42      阅读:379      评论:0      收藏:0      [点我收藏+]

标签:

/*
求解单源最短路问题:Dijkstra算法(该图所有边的权值非负)
 
关键(贪心):
	(1)找到最短距离已经确定的节点,从它出发更新与其相邻节点的最短距离;
	(2)此后不再关心(1)中“最短距离已经确定的节点”。
 
时间复杂度(大概的分析,不准确):
	“找到最短距离已经确定的节点” => O(|V|)
	"从它出发更新与其相邻节点的最短距离" => 邻接矩阵:O(|V|),邻接表:O(|E|)
	需要循环以上两个步骤V次,所以时间复杂度:O(V^2)
	即:在|E|较小的情况下,时间主要花在了寻找最短距离已经确定的节点
 
	考虑用二叉堆(C++ priority_queue)实现,放入二叉堆数据的操作最多有|E|次,
	堆中的元素平均下来大概有|V|,故时间复杂度O(|E|log|V|)
 
	--------------------------------------------
	基础知识:
	C++ priority_queuehttp://www.cplusplus.com/reference/queue/priority_queue/?kw=priority_queue
	This context is similar to a heap, where elements can be inserted at any moment, and only the max 
	heap element can be retrieved (the one at the top in the priority queue). 
	缺省情况下,priority_queue利用一个大根堆完成。

引自百度百科: 二叉堆:完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种:最大堆和最小堆。 最大堆(大根堆):父结点的键值总是大于或等于任何一个子节点的键值; 最小堆(小根堆):父结点的键值总是小于或等于任何一个子节点的键值。 完全二叉树(Complete Binary Tree) 若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边, 这就是完全二叉树。 -------------------------------------------- 题目: poj 1860 Currency Exchange 利用最大路径来求,改变Dijkstra算法判断条件即可。 */
  1 #include <iostream>
  2 #include <cstdlib>
  3 #include <cstdio>
  4 #include <cstddef>
  5 #include <iterator>
  6 #include <algorithm>
  7 #include <string>
  8 #include <locale>
  9 #include <cmath>
 10 #include <vector>
 11 #include <cstring>
 12 #include <map>
 13 #include <utility>
 14 #include <queue>
 15 #include <stack>
 16 #include <set>
 17 #include <functional>
 18 using namespace std;
 19 typedef pair<double, int> P; // first:最大货币价值 second:the number of exchange points
 20 const int INF = 0x3f3f3f3f;
 21 const int modPrime = 3046721;
 22 const double eps = 1e-9;
 23 const int MaxN = 105;
 24 
 25 int N, M, S;
 26 double V;
 27 double d[MaxN];
 28 
 29 struct Edge
 30 {
 31     int to;
 32     double rate;
 33     double commission;
 34 };
 35 
 36 vector<Edge> G[MaxN];
 37 
 38 void Solve()
 39 {
 40     fill(d, d + MaxN, -1);
 41     d[S] = V;
 42     priority_queue<P, vector<P> > que;
 43     que.push(P(d[S], S));
 44     while (!que.empty())
 45     {
 46         P p = que.top();
 47         que.pop();
 48         int v = p.second;
 49         if ((v == S) && (p.first - V) > eps)
 50         {
 51             printf("YES\n");
 52             return;
 53         }
 54         if (d[v] > p.first)
 55         {
 56             continue;
 57             // 如果当前取出节点的货币值不是该节点的货币最大值,直接放弃这个节点货币值
 58             /*
 59             出现这种情况的原因是:
 60             不断向二叉堆中放入更新过的数据{p.first, p.second},但是有可能同一个节点多次更新,
 61             导致放入二叉堆这样一些节点:节点相同(p.second相同),节点货币值不同(p.first不同)。
 62             例如假设当前二叉堆中依次放入{p.first1, p.second1},{p.first2, p.second1},{p.first3, 
 63             p.second1},可知 max{p.first1, p.first2, p.first3} = p.first3,此时d[p.second]已被
 64             更新为p.first3,那么当从二叉堆中取出{p.first1, p.second1},{p.first2, p.second1}时,
 65             直接舍弃掉即可,因为在取出前两者之前,{p.first3, p.second1}已被取出,并且已利用{p.first3, 
 66             p.second1}更新了其他节点的货币值(priority_queue: only the max heap element can be 
 67             retrieved (the one at the top in the priority queue).)。
 68             */
 69         }
 70         for (int i = 0; i < G[v].size(); ++i)
 71         {
 72             Edge eg = G[v][i];
 73             if (d[eg.to] < (d[v] - eg.commission)*eg.rate)
 74             {
 75                 d[eg.to] = (d[v] - eg.commission)*eg.rate;
 76                 que.push(P(d[eg.to], eg.to));
 77             }
 78         }
 79     }
 80     printf("NO\n");
 81 }
 82 
 83 int main()
 84 {
 85 #ifdef HOME
 86     freopen("in", "r", stdin);
 87     //freopen("out", "w", stdout);
 88 #endif
 89 
 90     scanf("%d %d %d %lf", &N, &M, &S, &V);
 91     for (int i = 0; i < M; ++i)
 92     {
 93         int currency1, currency2;
 94         scanf("%d %d", &currency1, &currency2);
 95         Edge eg;
 96         eg.to = currency2;
 97         scanf("%lf %lf", &eg.rate, &eg.commission);
 98         G[currency1].push_back(eg);
 99 
100         eg.to = currency1;
101         scanf("%lf %lf", &eg.rate, &eg.commission);
102         G[currency2].push_back(eg);
103     }
104 
105     Solve();
106 
107 #ifdef HOME
108     cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl;
109     _CrtDumpMemoryLeaks();
110 #endif
111     return 0;
112 }

 

 

 

 

Dijkstra算法(求解单源最短路)详解 + 变形 之 poj 1860 Currency Exchange

标签:

原文地址:http://www.cnblogs.com/shijianming/p/5031243.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!