所有节点对之间的最短路问题(All Pair Shortest Path)--《算法导论》
2016-08-28 23:52
429 查看
给定一个有向图求出里面所有节点对之间的最短路径。
问题的详细描述见Wikipedia:https://en.wikipedia.org/wiki/Shortest_path_problem。
介绍两个算法O(V3)的Floyd算法和O(V2lgV+VE)的Jhonson算法。分别应对稠密图和稀疏图的情况。
dkij={wijmin{dk−1ij,dk−1ik+dk−1ij}x=0x!=0
伪代码
for k=1 to |V|
for i=1 to V
for j=1 to V
d[i][j]=min{d[i][j],d[i][k]+d[k][j]}
c++代码
重塑权重值
设p:<v0,...,vi,...,vk>为从v0到vk的一条最短路,则重塑的权重w′必须满足两个条件:
1、w(p)=δ(v0,vk)⇔w′(p)=δ(v0,vk)
2、w(p)不包含负环⇔ w′(p)不包含负环
下面证明取权重映射w′(u,v)=w(u,v)+h(u)−h(v)时满足条件。
w′(p)=∑ni=1w′(vi,vi−1)
=∑ni=1w(vi,vi−1)+h(v0)−h(vk)
=w(p)+h(v0)−h(vk)
第一条肯定满足了,因为h(v0),h(vk)是预处理出来的常数,第二条,当p为一负权重的环路时,v0=vk,所以w′(p)=w(p)也是负环。
构造函数h
我们采取的方法是这样的,添加一新节点编号为0,到每一个顶点的距离为0,然后我们令h(v)=δ(0,v),由三角不等式h(v)≤h(u)+w(u,v),所以w′(u,v)≥0
简单写一下伪代码
伪代码
compute G′
spfa(G’,0)
foreach vertex v ∈G.V
h(v)=δ(0,v)
foreach edge (u,v)∈G.E
w′(u,v)=w(u,v)+h(u)−h(v)
foreach vertex v ∈G.V
Dijkstra(G,v)
for i=1 to V
forj=1 to V
d[i][j]=d[i][j]+h[j]−h[i]
c++代码
Johnson算法实现太复杂,在V不是很大的时候都建议用floyd。
代码测试题poj 1125。。。。就是water problem了。。。
问题的详细描述见Wikipedia:https://en.wikipedia.org/wiki/Shortest_path_problem。
介绍两个算法O(V3)的Floyd算法和O(V2lgV+VE)的Jhonson算法。分别应对稠密图和稀疏图的情况。
Floyd
这是一个动态规划算法。设dkij是i,j之间所有中间节点全部取自<1,2,...,i,...,k>的一条最短路的权重。则状态转移方程如下dkij={wijmin{dk−1ij,dk−1ik+dk−1ij}x=0x!=0
伪代码
for k=1 to |V|
for i=1 to V
for j=1 to V
d[i][j]=min{d[i][j],d[i][k]+d[k][j]}
c++代码
void floyd(int n) { memcpy(d,w,sizeof(w));//初始化d(0) for(int k=1 ; k<=n ; ++k) for(int i= 1 ; i<=n ; ++i) for(int j=1 ; j<=n ; ++j) d[i][j] = min(d[i][j],d[i][k]+d[k][j]); }
Johnson(用于稀疏图)
Johnson算法的核心思想是直接对每个顶点做一次Dijkstra,这样时间复杂度只有O(VElgV)(用斐波那契堆实现只需O(V2lgV))对于稀疏图来说是会渐进优于Floyd算法的,但是我们知道Dijkstra算法只能用于权重为正数的情况。所以要对图上的权重进行重新映射一次。重塑权重值
设p:<v0,...,vi,...,vk>为从v0到vk的一条最短路,则重塑的权重w′必须满足两个条件:
1、w(p)=δ(v0,vk)⇔w′(p)=δ(v0,vk)
2、w(p)不包含负环⇔ w′(p)不包含负环
下面证明取权重映射w′(u,v)=w(u,v)+h(u)−h(v)时满足条件。
w′(p)=∑ni=1w′(vi,vi−1)
=∑ni=1w(vi,vi−1)+h(v0)−h(vk)
=w(p)+h(v0)−h(vk)
第一条肯定满足了,因为h(v0),h(vk)是预处理出来的常数,第二条,当p为一负权重的环路时,v0=vk,所以w′(p)=w(p)也是负环。
构造函数h
我们采取的方法是这样的,添加一新节点编号为0,到每一个顶点的距离为0,然后我们令h(v)=δ(0,v),由三角不等式h(v)≤h(u)+w(u,v),所以w′(u,v)≥0
简单写一下伪代码
伪代码
compute G′
spfa(G’,0)
foreach vertex v ∈G.V
h(v)=δ(0,v)
foreach edge (u,v)∈G.E
w′(u,v)=w(u,v)+h(u)−h(v)
foreach vertex v ∈G.V
Dijkstra(G,v)
for i=1 to V
forj=1 to V
d[i][j]=d[i][j]+h[j]−h[i]
c++代码
void spfa(int s) { for(int i=1 ; i<=nv ; ++i)d[s][i] = INF; d[s][s] = 0; memset(inq,false,sizeof(inq)); queue<int> q; q.push(s); inq[s] = true; while(!q.empty()) { int u =q.front(); q.pop(); inq[u] = false; for(int i=first[u] ; i!=-1 ; i = nt[i]) { Edge &e = edges[i]; if(d[s][e.to]>d[s][u]+e.weight) { d[s][e.to]=d[s][u]+e.weight; if(!inq[e.to]){ q.push(e.to);inq[e.to] = true; } } } } } void dijkstra(int s) { bool vis[MAX_V]; memset(vis,false,sizeof(vis)); for(int i=1 ; i<=nv ; ++i)d[s][i] = INF; d[s][s] = 0; priority_queue<pii,vector<pii>,greater<pii> > q; q.push(pii(0,s)); while(!q.empty()) { int u = q.top().second;q.pop(); if(vis[u])continue; else vis[u] = true; for( int i=first[u] ; i!=-1 ; i = nt[i]) { Edge& e = edges[i]; if(d[s][e.to]>d[s][u]+e.weight) { q.push(pii(d[s][e.to],e.to)); d[s][e.to] = d[s][u]+e.weight ; } } } } void compute_Go(int last_edge)//最后一条边编号 { int id = last_edge+1; for(int i=1 ; i<=nv ;++i ) { read_edge(0,i,0,id);//向边集数组添加新边 id++; } } void johnson() { int h[MAX_V]; compute_Go(ne); spfa(0); for(int i=1 ; i<=nv ;++i)h[i] = d[0][i]; //重塑边权重 for(int i=1 ; i<=ne ;++i) { Edge &e = edges[i]; e.weight = e.weight+h[e.from]-h[e.to]; } for(int i=1 ; i<=nv ; ++i) { dijkstra(i); } //映射回原来的最短路径 for(int i=1 ;i<=nv ;++i) { for(int j=1 ; j<=nv ; ++j) d[i][j] = d[i][j]+h[j]-h[i]; } }
Johnson算法实现太复杂,在V不是很大的时候都建议用floyd。
代码测试题poj 1125。。。。就是water problem了。。。
相关文章推荐
- NEU 1685: All Pair Shortest Path
- ICPCCamp 2016 Day1 ftiasch's Contest #4(All Pair Shortest Path-位运算)
- Floyd All Shortest Path 所有最短路径的查找 C++程序
- 第十五章 GRL_1_C:All Pairs Shortest Path 所有点对间最短路径
- ICPCCamp2016day 1 - All Pair Shortest Path【bitset优化】
- ICPCCamp 2016 Day 1 - B All Pair Shortest Path (bitset)
- 使用JavaScript展开/折叠TreeView中所有节点(Expand and Collapse All Nodes of asp.net Treeview on the client with javascript)
- 图的所有节点对之间的最短路径—Floyd算法(C++)
- 【原】用使用JavaScript展开/折叠TreeView中所有节点(Expand and Collapse All Nodes of asp.net Treeview on the client with javascript)
- 所有节点之间的最短路问题
- 算法导论 第二十五章 所有节点对的最短路径问题
- 求二叉树中的最大路径和,也就是求节点和节点之间的路径上所有节点的最大值
- 将链表中的所有元素为奇数的节点移到元素为偶数节点的前面,并使奇数之间顺序反转,偶数之间顺序反转
- 弗洛伊德算法模板 All Pairs Shortest Path Aizu - GRL_1_C
- LeetCode—***寻找二叉树中任意两个节点之间的最大值Binary Tree Maximum Path Sum
- 算法导论 所有节点对的最短路径问题 FloydWarshall
- 所有整数对之间的位差异数之和(Sum of bit differences among all pairs)
- 将链表中的所有元素为奇数的节点移到元素为偶数节点的前面,并保证奇数之间顺序不变,偶数之间顺序不变(创新工场)
- 将链表中的所有元素为奇数的节点移到元素为偶数节点的前面,并保证奇数之间顺序不变,偶数之间顺序不变(创新工场)
- 算法导论problem 24-5 Gabow's algorithm for single source shortest path