单源最短路径 Bellman_ford 和 dijkstra

首先两个算法都是常用于 求单源最短路径

关键部分就在于松弛操作 实际上就是dp的感觉

if (dist[e.to] > dist[v] + e.cost)

{

  dist[e.to] = dist[v] + e.cost;  

  ...

}

bellman_ford O(E*V) 但是配合队列可以 有spfa 可以达到O(kE)

http://www.360doc.com/content/13/1208/22/14357424_335569176.shtml

并且bellman_ford还适用于负边 并且可以利用最多循环V-1次的性质 判断是否存在负圈(如果循环超过V-1次 说明有负圈 因为没重复走着负圈一次 都伴随着更新)

并且因为松弛操作是针对于每条边的遍历也可以用向前星存

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <fstream>
 4 #include <string.h>
 5 #define MAXV 10007
 6 #define MAXE 1007
 7 #define INF 0x3f3f3f3f
 8 using namespace std;
 9
10 int V, E;
11
12 struct Edge
13 {
14     int from, to, cost;
15 }edge[MAXE];
16
17
18
19
20 int bellman_ford(int s, int d)//求单源最短路径
21 {
22     int dist[MAXV];
23     fill (dist, dist+V+10, INF);
24     dist[s] = 0;
25     while (true)//直至update不在更新
26     {
27         bool update = false;
28         for (int i = 0; i < E; i++)
29         {
30             if (dist[edge[i].from] != INF && dist[edge[i].to] > dist[edge[i].from] + edge[i].cost)
31             {
32                 dist[edge[i].to] = dist[edge[i].from] + edge[i].cost;
33                 update = true;
34             }
35         }
36         if (!update) break;
37     }
38     return dist[d];
39 }
40 //while(true) 循环中最多循环V-1次 复杂度是O(V*E)
41 //如果存在 从s可达的负圈 那么在第V次循环时也会更新 可以用这个性质来检查负圈
42 //如果一开始把dist都初始化为0  那么可以检查出所有的负圈
43 //检查负边 是负边 返回true
44 //P.S 圈表示基本回路
45 bool isNegtive()
46 {
47     int dist[MAXV];
48     memset(dist, 0, sizeof(dist));//单纯查负圈
49     for (int i = 0; i < V; i++)
50     {
51         for (int i = 0; i < E; i++)
52         {
53             Edge e = edge[i];
54             if (dist[e.to] < dist[e.from] + e.cost )
55             {
56                 dist[e.to] = dist[e.from] + e.cost;
57                 if (i == V-1)//如果第V次还更新 那么就有负圈
58                     return true;
59             }
60         }
61     }
62     return false;
63 }
64 int main()
65 {
66     ifstream cin ("in.txt");
67     cin >> V >> E;
68     for (int i = 0; i < E; i++)
69     {
70         cin >> edge[i].from >> edge[i].to >> edge[i].cost;
71     }
72     cout << bellman_ford(1, 7) << endl;
73 }

dijkstra 普通写法O(V^2)

但是 dijkstra的特点 --->>是针对每一个点 通过它所对应的边更新 e.to的节点

每次取出的是离原点sorce 最近的点 所以就可以使用优先队列 那么就变成O(V*logV)

并且因为“是针对每一个点 通过它所对应的边更新 e.to的节点 ” 那么也很好试用向前星

  1 #include <iostream>
  2 #include <string.h>
  3 #include <fstream>
  4 #include <stdio.h>
  5 #include <queue>
  6 #define MAXV 10007
  7 #define MAXE 1007
  8 #define INF 0x3f3f3f3f
  9 using namespace std;
 10
 11 int V, E;
 12 //迪杰特斯拉好像不是很好用向前星
 13 //这个算法是针对每一个点更新 而向前星存储的是边的信息 要查找点就比较复杂
 14
 15 //用邻接矩阵存储 O(V^2)的算法
 16
 17 int cost[MAXV][MAXV];
 18 int dijkstra(int s, int d)
 19 {
 20     int dist[MAXV];
 21     bool use[MAXV];
 22     fill(dist, dist+MAXV, INF);
 23     memset(use, false, sizeof(use));
 24     dist[s] = 0;
 25     while (true)
 26     {
 27         int v = -1;
 28         for (int i = 1; i <= V; i++)//找一个最近的 未使用过的点
 29         {
 30             if (!use[i] && (v == -1 || dist[i] < dist[v])) v = i;
 31         }
 32         if (v == -1) break;
 33         use[v] = true;
 34         for (int i = 1; i <= V; i++)
 35         {
 36             dist[i] = min(dist[i], dist[v] + cost[v][i]);
 37         }
 38     }
 39     return dist[d];
 40 }
 41
 42 //使用优先队列(也就是heap优化)O(E*logV)
 43 //针对边来dp 这里可以用向前星存储了
 44 struct Edge
 45 {
 46     int to, n, next;
 47 }edge[MAXE];
 48 int num = 0;
 49 int head[MAXV];
 50 void Add(int from, int to, int c)
 51 {
 52     edge[num].n = c;
 53     edge[num].to = to;
 54     edge[num].next = head[from];//从头插入
 55     head[from] = num++;
 56 }
 57 void init()//初始化
 58 {
 59     ifstream cin("in.txt");
 60     memset(edge, -1, sizeof(edge));
 61     memset(head, -1, sizeof(head));
 62     cin >> V >> E;
 63     for (int j = 0; j < E; j++)
 64     {
 65         int from , to , c;
 66         cin >> from >> to >> c;
 67         Add(from, to, c);
 68     }
 69 }
 70
 71 typedef pair<int, int> P;//first 表示与s的距离, second表示点的编号
 72 int pre[MAXV];//记录前驱节点 在每次dist[j] = dist[k] + cost[k][j]更新时记录在到j的最短路径上的前驱节点就是k
 73 int fast_dijkstra(int s, int d)
 74 {
 75     int dist[MAXV];
 76     priority_queue<P, vector<P>, greater<P> > que;//用优先队列存储点的信息 每次弹出距离最短的点O(logV)
 77     fill(dist, dist+MAXV, INF);
 78     dist[s] = 0;
 79     que.push(P(0, s));
 80     while (!que.empty())
 81     {
 82         P p = que.top();
 83         que.pop();
 84         if (dist[p.second] < p.first) continue;
 85         int t = head[p.second];
 86         while (t != -1)
 87         {
 88             Edge e = edge[t];
 89             if (dist[e.to] > dist[p.second] + e.n)
 90             {
 91                 dist[e.to] = dist[p.second] + e.n;
 92                 pre[e.to] = p.second;
 93                 que.push( P(dist[e.to], e.to) );
 94             }
 95             t = e.next;
 96         }
 97     }
 98     return dist[d];
 99 }
100
101 int main()
102 {
103     /*
104     ifstream cin("in.txt");
105     cin >> V >> E;
106     for (int i = 1; i <= V; i++)
107         for (int j = 1; j <= V; j++)
108             cost[i][j] = INF;//不存在时 cost为INF
109     for (int j = 0; j < E; j++)
110     {
111         int from , to , c;
112         cin >> from >> to >> c;
113         cost[from][to] = c;
114     }
115     int ans = dijkstra(1, 7);
116     */
117     init();
118     int ans = fast_dijkstra(1,7);
119     cout << ans << endl;
120     //这样路径即还原了
121     int t = pre[7];
122     cout << 7 << " ";
123     while(t != 1)
124     {
125         cout << t << " ";
126         t = pre[t];
127     }
128     cout << 1 <<endl;
129 }
时间: 2024-12-19 09:15:48

单源最短路径 Bellman_ford 和 dijkstra的相关文章

图论(四)------非负权有向图的单源最短路径问题,Dijkstra算法

Dijkstra算法解决了有向图G=(V,E)上带权的单源最短路径问题,但要求所有边的权值非负. Dijkstra算法是贪婪算法的一个很好的例子.设置一顶点集合S,从源点s到集合中的顶点的最终最短路径的权值均已确定.算法反复选择具有最短路径估计的顶点u,并将u加入到S中,对u 的所有出边进行松弛.如果可以经过u来改进到顶点v的最短路径的话,就对顶点v的估计值进行更新. 如上图,u为源点,顶点全加入到优先队列中. ,队列中最小值为u(值为0),u出队列,对u的出边进行松弛(x.v.w),队列最小值

数据结构与算法--单源最短路径算法之dijkstra

单源最短路径之dijkstra算法 最优子问题:dis(s,...,e)是s到e的最短路径,在这条路径上的所有点之间dis(pi,pj)距离是最小的. 算法思路: 首先初始化,dis[s][i]是s到i的距离,直接相连的就是其距离,不直接相连的就是无穷大 下面是算法主要模块: 1.选取dis[i]最小的点加入到P{S}中, 2.计算是否更新dis[j],j是和i直接相连的 3.重复以上步骤,直到e

算法导论--单源最短路径问题(Dijkstra算法)

转载请注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51918844 单源最短路径是指:给定源顶点s∈V到分别到其他顶点v∈V?{s}的最短路径的问题. Dijkstra算法采用贪心策略:按路径长度递增的顺序,逐个产生各顶点的最短路径.算法过程中需要维护一个顶点集S,此顶点集保存已经找到最短路径的顶点.还需要维护一个距离数组dist, dist[i]表示第i个顶点与源结点s的距离长度. Dijkstra算法思路: S

数据结构:单源最短路径--Dijkstra算法

Dijkstra算法 单源最短路径 给定一带权图,图中每条边的权值是非负的,代表着两顶点之间的距离.指定图中的一顶点为源点,找出源点到其它顶点的最短路径和其长度的问题,即是单源最短路径问题. Dijkstra算法 求解单源最短路径问题的常用方法是Dijkstra(迪杰斯特拉)算法.该算法使用的是贪心策略:每次都找出剩余顶点中与源点距离最近的一个顶点. 算法思想 带权图G=<V,E>,令S为已确定了最短路径顶点的集合,则可用V-S表示剩余未确定最短路径顶点的集合.假设V0是源点,则初始 S={V

Dijkstra算法求单源最短路径

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

单源最短路径 dijkstra算法实现

本文记录一下dijkstra算法的实现,图用邻接矩阵表示,假设图为无向图,并且连通,有向图,不连通图的做法类似. 算法简述: 首先确定"单源"的源,假设是第0个顶点. 维护三个数组dist[], color[], path[],设其下标分别为0-i-n-1: dist[] 表示源点到顶点i的最短距离,在初始化时,如果源点到顶点i有路径,则初始化为路径的权重,否则初始化为INT_MAX: color[] 数组其实表示两个集合,即color[i]值为1的集合表示已经确定最短路径的点的集合,

dijkstra 两点的最短路径 单源 最短路径

思路以dist数组 来扩充  路径的访问,不断的刷新dist数组 设置一个顶点的集合s,并不断地扩充这个集合,一个顶点属于集合s当且仅当从源点到该点的路径已求出.开始时s中仅有源点,并且调整非s中点的最短路径长度,找当前最短路径点,将其加入到集合s,直到终点在s中.基本步骤:1.把所有结点分成两组:      第一组:包括已经确定最短路径的结点:      第二组:包括尚未确定最短路径的结点.2.开始时,第一组只包含起点,第二组包含剩余的点:3.用贪心的策略,按最短路径长度递增的顺序把第二组的结

单源最短路径算法---Dijkstra

Dijkstra算法树解决有向图G=(V,E)上带权的单源最短路径问题,但是要求所有边的权值非负. 解题思路: V表示有向图的所有顶点集合,S表示那么一些顶点结合,从源点s到该集合中的顶点的最终最短路径的权值(程序中用dist[i]表示)已经确定.算法反复选择具有最短路径估计的顶点u 属于 V-S(即未确定最短路径的点,程序中finish[i]=false的点),并将u加入到S中(用finish[i]=true表示),最后对u的所有输出边进行松弛. 程序实现:      输入数据: 5 7 0

图的单源最短路径:Dijkstra算法实现

本文介绍的是图的非负权值的单源最短路径问题.问题的提出是,对于有权图D,t提供源点v,要找到从v到其他所有点的最短路径,即单源最短路径问题,在本文中,解决这一问题,是普遍比较熟悉的Dijkstra算法. 算法核心思想参见维基.简而言之,设集合S存放已经求出了最短路径的点.初始状态S中只有一个点v0,之后每求得v0到vn的最短路径,就会更新v0到所有vn邻接的点的一致的最短路径(不一定是最终的最短路径),如此重复,每次会确定v0到一个点的最短路径,确定好的点加入S中,直至所有点进入S结束.在本文中