单源最短路径 Bellman_Ford
来源:互联网 发布:淘宝友邦电器城假货 编辑:程序博客网 时间:2024/05/21 20:26
一、问题简述
Dijkstra算法无法判断含负权边的图的最短路。如果遇到负权,在没有负权回路(回路的权值和为负,即便有负权的边)存在时,也可以采用Bellman - Ford算法正确求出最短路径。
Bellman-Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题。对于给定的带权(有向或无向)图 G=(V,E), 其源点为v0。
接下来分析回路问题,如果有正回路,则动态规划会因为松弛操作选出最优答案,必然是不会走重复回路的,那么n-1个节点就能找到再也无法松弛的结果,无须担心。但是如果是负回路,那么步数越多,则距离越小,所以对最后结果再进行松弛操作,也是可以找到答案的。
如果不存在这样的负回路,算法将给出从源点s到 图G的任意顶点v的最短路径d[v]。
附:松弛操作
二、算法思想
首先:初始化邻接矩阵
其次:进行不断的松弛操作(bellman函数)
另外:再把每次松弛时把每条边都更新一下,若在n-1次松弛后还能更新,则说明图中有负环,因此无法得出结果(minus函数)。
最后:path函数去寻找路径
三、具体代码
#include <iostream>#include<stack>#include<stdio.h>#include<stdlib.h>#include<iostream>#include<queue>#include<climits>#include<cstring>using namespace std;struct node0{ int kdist; int dist; int path;};int i,j,k;int bellman( int **graph,node0 *node,int v0,int n) //v0表示源顶点 { for(int j=0;j<n;j++) //初始化 完成 { node[j].kdist=graph[v0][j]; node[j].dist=graph[v0][j]; node[j].path=v0; //path记录最短路径上从v0到i的前一个顶点 if(graph[v0][j]==INT_MAX) node[j].path=-1; } //完成表格 node[n-1][0到n-1],也即所有节点,在最多经过n-1个其它节点之后,最短路径问题 for(int k=2;k<n;k++) { //接下来目的是完成:任意一个节点u,在最多经过k个其它节点之后的最短路径为node[k][u]; 并且接下来把node[k-1][i]称为i离源点的现有最短距离。 i是u的相邻节点 for(int u=0;u<n;u++) { int temp=INT_MAX;int tempfrom=-1; for(int i=0;i<n;i++) { if(node[i].kdist!=INT_MAX&&graph[i][u]!=INT_MAX&&i!=u &&temp>node[i].kdist+graph[i][u]) //目前这个关联节点的现有最短距离不能是无穷远, //这两个节点是相邻节点,距离不是无穷远 //可以松弛操作:(相邻节点i自身到源点的现有距离和ui之间的距离之和、要比u到源点的现有距离远) { temp=node[i].kdist+graph[i][u]; tempfrom=i;//存下来i当作前向节点 } } node[u].path=tempfrom;// 记住最后完成松弛操作的前向节点 int tempkdist=node[u].kdist; node[u].kdist=node[u].dist; node[u].dist=min(tempkdist,temp) ; } }}int minus0(int **graph,node0 *node,int n)//判断是否有负回路。现在经过了n-1个点得到最短路径node[u].dist,那么如果有负回路,则再经过别的点,可以让路径更短,对最后结果进行一次松弛操作判断 { for(int u=0;u<n;u++) { int temp=INT_MAX;int tempfrom=-1; for(int i=0;i<n;i++) { if(node[i].dist!=INT_MAX&&graph[i][u]!=INT_MAX&&i!=u &&temp>node[i].dist+graph[i][u]) { temp=node[i].dist+graph[i][u]; tempfrom=i;//存下来i当作前向节点 } } if(temp<node[u].dist)//注意是dist。 { return -1;} } return 0;}void showPath(node0 *node,int i,int v0,int n) //打印最短路径上的各个顶点 { int *store=(int *)malloc(sizeof(int)*n); int count=0; while(i!=v0) { store[count++]=i; i=node[i].path; //node[n-1][u].path里面存着的都是最后也即最好的让它完成松弛操作的前向节点 } store[count]=v0; for(int j=count;j>=0;j--) cout<<store[j]<<ends; free(store);} void input(int **graph,int n,int edge)//完成邻接矩阵{ int i,j; int from,to,weight; int v0; for(i=0;i<n;i++) { for(j=0;j<n;j++) { if(i!=j) graph[i][j]=INT_MAX; } graph[i][i]=0; } cout<<"请输入from,to,weight"<<endl; for (int i = 0; i < edge; i++) { fin>>from>>to>>weight; graph[from][to]=weight; } }int main(){ int n,edge,v0; //表示输入的顶点数和边数 cout<<"请输入节点和边数"<<endl; cin>>n>>edge; cout<<"请输入源点"<<endl; fin>>v0; int **graph; graph=new int *[n+1];//n行,n列。 for(int i=0;i<n;i++) graph[i]=new int [n+1]; input(graph,n,edge); node0 *node; node=new node0[n+1];//num+1行,all+1列。 int lookme; bellman(graph,node,v0,n); lookme=minus0(graph,node,n); if(lookme==-1) cout<<"警告!警告!存在负环路!系统即将关闭"<<endl; else for(int i=0;i<n;i++) { if(i!=v0) { if(node[i].dist!=INT_MAX) { cout<<i<<"的路径是"; showPath(node,i,v0,n); cout<<endl<<" 距离为"<<node[i].dist<<endl; } else cout<<i<<"无法到达"<<endl; } }}
四、实验结果
5 10 0
0 1 6
0 3 7
1 2 5
1 4 -4
1 3 8
3 2 -3
3 4 9
2 1 -2
4 3 7
4 0 2
0 0
- 单源最短路径 Bellman_Ford
- 单源最短路径Bellman_Ford算法C++实现
- 单源最短路径Bellman_Ford算法C++实现
- Bellman_Ford算法求最短路径
- 单源最短路径:Dijkstra 算法 Bellman_Ford 算法 SPFA 算法
- 最短路径之Bellman_Ford
- bellman_ford
- 图算法 单源最短路径 Bellman_Ford算法(边权值为负情况)
- 数据结构与算法系列----单源最短路径(Dijkstra算法&Bellman_Ford算法)
- 最短路径——Bellman_Ford算法
- 【最短路径-Floyd/Bellman_Ford】hdu 1217 Arbitrage
- 含有负边的图的最短路径(Bellman_ford算法)
- 经典算法之图的最短路径(二):Bellman_Ford算法
- 求解最短路径Bellman_Ford 算法优化版——结合队列
- ACM中的图中关于最短路径的dijistra算法和bellman_ford算法
- Bellman_Ford模板
- Bellman_Ford POJ3259
- zju3033(bellman_ford)
- C++——KMP模板
- Java——线程正常停止
- 色阶
- 缓存技术
- 兼容IE7+的rgba()的方法
- 单源最短路径 Bellman_Ford
- c库函数和系统函数的关系
- 单例模式
- margin:auto实现居中
- PDO抽象层处理数据库
- Gradle sync failed: 'com.android.build.gradle.BasePlugin' does not implement the Plugin interface
- ABAP取域值
- 完美字符串 贪心
- 在 Finder 里直接显示图片尺寸信息