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

/*
求解单源最短路问题: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_queue:http://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 }

 
 
时间: 2024-08-03 15:40:24

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

hdu1874 畅通工程续(Dijkstra算法,单源最短路)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1874 畅通工程续 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 36359    Accepted Submission(s): 13355 Problem Description 某省自从实行了很多年的畅通工程计划后,终于修建了很多路.

Dijkstra算法求单源最短路径

1.最短路径 在一个连通图中,从一个顶点到另一个顶点间可能存在多条路径,而每条路径的边数并不一定相同.如果是一个带权图,那么路径长度为路径上各边的权值的总和.两个顶点间路径长度最短的那条路径称为两个顶点间的最短路径,其路径长度称为最短路径长度. 最短路径在实际中有重要的应用价值.如用顶点表示城市,边表示两城市之间的道路,边上的权值表示两城市之间的距离.那么城市A到城市B连通的情况下,哪条路径距离最短呢,这样的问题可以归结为最短路径问题. 求最短路径常见的算法有Dijkstra算法和Floyd算法

最短路(Bellman_Ford) POJ 1860 Currency Exchange

题目传送门 1 /* 2 最短路(Bellman_Ford):求负环的思路,但是反过来用,即找正环 3 详细解释:http://blog.csdn.net/lyy289065406/article/details/6645778 4 */ 5 #include <cstdio> 6 #include <iostream> 7 #include <algorithm> 8 #include <cstring> 9 #include <vector>

利用分支限界法求解单源最短路(Dijkstra)问题

分支限界法定义:采用BFS算法,并使用剪枝函数的算法称为分支界限法. 分支限界法解释:按广度优先的原则,有选择的在其child中进行扩展,从而舍弃不含有最优解的分支,不断重复这一过程,直到找到答案或者判定无解. 分支界限法常常用到优先队列来选择最佳扩展节点,有时也会用到普通队列,以先进先出为原则来进行筛选. 单源最短路问题定义:给定有向图和起点,寻找到达所有点的最短路径. 单源最短路的分支限界法概述:首先把节点加入优先队列,之后不断地从队列中取出最优扩展点,观察其可抵达的所有目标节点,若当前路径

再看最短路算法 1 —— 单源最短路

学了多年的算法,最短路问题相当之常见———— 好久没写过最短路的问题了,直到昨天闲的无聊来了一题——BZOJ3402(HansBug:额才发现我弱到只能刷水的地步了TT) 一看这不是明显的单源最短路么呵呵...于是直接上来来了个dijkstra,而且用的是邻接表存储图—— Submit之后,结果却是—— 我立刻被雷到了QAQ...于是立刻改写spfa,结果—— 4000ms+(估计还不止)和192ms究竟是怎样的差距啊QAQ,本人虽然早都听说过spfa的强大性,但是未曾想过差距会如此可怕,于是H

用scheme语言实现SPFA算法(单源最短路)

最近自己陷入了很长时间的学习和思考之中,突然发现好久没有更新博文了,于是便想更新一篇. 这篇文章是我之前程序设计语言课作业中一段代码,用scheme语言实现单源最段路算法.当时的我,花了一整天时间,学习了scheme并实现了SPFA算法,那天实现之后感觉很有成就感-在这里贴出来,以飨读者. 突然发现博客园不支持scheme语言,于是只能放弃高亮了.不得不说,scheme代码有没有高亮差别好大…… ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; 题目

Til the Cows Come Home(poj 2387 Dijkstra算法(单源最短路径))

Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 32824   Accepted: 11098 Description Bessie is out in the field and wants to get back to the barn to get as much sleep as possible before Farmer John wakes her for the morning milking. Bessi

Dijkstra算法详细(单源最短路径算法)

介绍 对于dijkstra算法,很多人可能感觉熟悉而又陌生,可能大部分人比较了解bfs和dfs,而对dijkstra和floyd算法可能知道大概是图论中的某个算法,但是可能不清楚其中的作用和原理,又或许,你曾经感觉它很难,那么,这个时候正适合你重新认识它. Dijkstra能是干啥的? Dijkstra是用来求单源最短路径的 就拿上图来说,假如直到的路径和长度已知,那么可以使用dijkstra算法计算南京到图中所有节点的最短距离. 单源什么意思? 从一个顶点出发,Dijkstra算法只能求一个顶

山东省第七届ACM竞赛 C题 Proxy (Dijkstra算法,单源路径最短问题)

题意:给定0-n+1个点,和m条边,让你找到一条从0到n+1的最短路,输出与0相连的结点... 析:很明显么,是Dijkstra算法,不过特殊的是要输出与0相连的边,所以我们倒着搜,也是从n+1找到0, 那么不就能找到与0相连的边么,注意判断相等值的时候.当时写错了好多次,就是没有考虑好边界. 代码如下: #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #