最短路之bellman-ford
来源:互联网 发布:支付宝付款需要网络吗 编辑:程序博客网 时间:2024/05/22 09:01
针对dijkstra不能解决负权边而有的时间复杂度比较高的算法。
单源最短路径,时间复杂度为O(n^3)
要求:不能存在负权回路,但是可以反映出这一情况。
运用松弛技术,每个顶点v属于V,逐步减小,源S到v的最短路径的估计值d[v],直至其
达到最短路径的权(s,v),...
Bellman-ford(G,w,s)
INITIALIZE-SINGLE-SOURCE(G,s)
FOR i <-- to |V(G)-1|
do for each edge(u,v) 属于 E(G)
do relax (u,v,w)
for each edge(u,v) 属于 E[G]
do if d[v]>d[u]+w[u,v]
then return false
return true
与dijkstra的区别是bellman没用贪心,而是暴力不断迭代,所以其时间规模较dijkstra有点大。
递推:
dist(1)[u]=edge[v0][u]
dist(k)[u]=min{dist(k-1)[u],min{dist(k-1)[j]+edge[j][u]}}
可优化为:
dist(0)[v]=inf,dist(0)[v0]=0
dist(k)[v]=min{dist(k-1)[v],dist(k-1)[u]+w[u,v]}
dist(1)[u]表示从原点v0到u的只经过一条边的最短路径长度
dist(n-1)[u]表示从原点v0到u(不形成回路)经过n-1条边的最短路径长度
递推实现代码:
#include<iostream>#include <cstdio>#define inf 1000000#define maxn 8int n;int Edge[maxn][maxn];int dist[maxn];int pre[maxn];using namespace std;bool bellman(int v0){int i,j,k,u,temp;for(i=0;i<n;i++){dist[i]=Edge[v0][i];if(i!=v0&&dist[i]<inf)pre[i]=v0;else pre[i]=-1;}for(k=2;k<n;k++){for(u=0;u<n;u++){if(u!=v0){for(j=0;j<n;j++){if(Edge[j][u]<inf&&dist[j]+Edge[j][u]<dist[u]){dist[u]=dist[j]+Edge[j][u];pre[u]=j;}}}}}for(i=0;i<n;i++){for(j=0;j<n;j++){if(Edge[i][j]<inf&&dist[i]+Edge[i][j]<dist[j]) return false;}}return true;}int main(){bool flag;int i,j;int u,v,w;scanf("%d",&n);while(scanf("%d%d%d",&u,&v,&w)){if(u==-1&&v==-1&&w==-1) break;Edge[u][v]=w;}for(i=0;i<n;i++){for(j=0;j<n;j++){if(i==j) Edge[i][j]=0;else if(Edge[i][j]==0) Edge[i][j]=inf;}}flag=bellman(0);if(flag){int shortest[maxn];for(i=1;i<n;i++){printf("%d\t",dist[i]);memset(shortest,0,sizeof(shortest));int k=0;shortest[k]=i;while(pre[shortest[k]]!=0){k++;shortest[k]=pre[shortest[k-1]];}k++;shortest[k]=0;for(j=k;j>0;j--)printf("%d->",shortest[j]);printf("%d\n",shortest[0]);}}else printf("error\n");return 0;}/*70 1 60 2 50 3 51 4 -12 1 -22 4 13 2 -23 5 -14 6 35 6 3-1 -1 -1*/
改过的代码:
bool bellman(int v0){int i,j,k,u,temp,S[maxn];for(i=0;i<n;i++){S[i]=0;dist[i]=Edge[v0][i];if(i!=v0&&dist[i]<inf)pre[i]=v0;else pre[i]=-1;}S[v0]=1;for(i=0;i<n;i++){u=v0,temp=inf;for(j=0;j<n;j++){if(!S[j]&&dist[j]<temp)u=j,temp=dist[j];}S[u]=1;for(k=0;k<n;k++){if(!S[k]&&Edge[u][k]&&dist[k]>dist[u]+Edge[u][k])dist[k]=dist[u]+Edge[u][k],pre[k]=u;}}for(k=2;k<n;k++){for(u=0;u<n;u++){if(u!=v0){for(j=0;j<n;j++){if(Edge[j][u]<inf&&dist[j]+Edge[j][u]<dist[u]){dist[u]=dist[j]+Edge[j][u];pre[u]=j;}}}}}for(i=0;i<n;i++){for(j=0;j<n;j++){if(Edge[i][j]<inf&&dist[i]+Edge[i][j]<dist[j]) return false;}}return true;}
若采用邻接表做bellman-ford时间复杂度将下降为O(n*m)
bool bellman(int v0){int i,k;for(i=0;i<n;i++){dist[i]=inf;pre[i]=-1;}dist[v0]=0;for(k=2;k<n;k++){for(i=0;i<n;i++){if(dist[Edge[i].u]!=inf&&Edge[i].w+dist[Edge[i].u]<dist[Edge[i].v]){dist[i].v=Edge[i].w+dist[Edge[i].u];pre[Edge[i].v]=Edge[i].u;}}}for(i=0;i<m;i++){if(dist[Edge[i].u]!=inf&&Edge[i].w+dist[Edge[i].u]<dist[Edge[i].v])return false;}return true;}
bellman-ford还是用邻接表比较好,虽然存储是有些麻烦。
//
SPFA:
bellman-ford的队列实现,减少了不必要的冗余判断。时间复杂度为O(k*m),k为每个顶点入队的平均次数,对于通常的情况k==2.
初始时讲源点加入队列Q ,每次从队列中取出一个顶点,并对所有与他相邻的顶点进行松弛操作,若松弛成功则将其入队(改变过的u),重复操作,直至队列为空。
SPFA(G,w,s)
INITALIZE-SINGLE-SOURCE(G,s)
INITLALIZE-QUEUE(Q)
ENQUEUE(Q,s)
WHILE Q != NULL
do u <-- DLQUEUE(Q)
do tmp <-- d[v]
relax(u,v,w)
if(d[v]<tmp and v not in Q)
ENQUEUE(Q,v)
SPFA 算法和bfs有一定的相似性,不同的是bfs搜索中一个顶点出了队列就不可能再次被放入队列,但是spfa在一个顶点可能在出了队列之后再次被放入队列,也就是说一个顶点改进过其他顶点之后,过了一段时间后可能本身会被改进,于是再次用来改进其他顶点,这样反复迭代下去。
#include <cstdio>#include <iostream>#include <sstream>#include <cstring>#include <cmath>#include <string>#include <vector>#include <stack>#include <queue> #include <set>#include <map>#include <algorithm>#define inf 1000000#define maxn 10using namespace std;struct ArcNode{int to;int weight;ArcNode *next;};queue <int >Q;//队列中的节点为顶点序号。int n;ArcNode *list[maxn];//每个顶点的边链表表头指针int inq[maxn];int dist[maxn];int pre[maxn];void SPFA(int v0){int i,u;ArcNode *temp;for(i=0;i<n;i++){dist[i]=inf;pre[i]=v0;inq[i]=0;}dist[v0]=0;pre[v0]=v0;inq[v0]++;Q.push(v0);while(!Q.empty ()){u=Q.front ();Q.pop ();inq[u]--;temp=list[u];while(temp!=NULL){int v=temp->to;if(dist[v]>dist[u]+temp->weight){dist[v]=dist[u]+temp->weight;pre[v]=u;if(!inq[v]) {Q.push (v);inq[v]++;}}temp=temp->next;}}}int main(){int i,j;int u,v,w;scanf("%d",&n);memset(list,0,sizeof(list));ArcNode *temp;while(~scanf("%d%d%d",&u,&v,&w)){if(u==-1&&v==-1&&w==-1) break;temp=new ArcNode;temp->to=v;temp->weight=w;temp->next=NULL;if(list[u]==NULL) list[u]=temp;else {temp->next=list[u];list[u]=temp;}}SPFA(0);for(j=0;j<n;j++)//释放空间{temp=list[j];while(temp!=NULL){list[j]=temp->next;delete temp;temp=list[j];}}int shortest[maxn];for(i=1;i<n;i++){printf("%d\t",dist[i]);memset(shortest,0,sizeof(shortest));int k=0;shortest[k]=i;while(pre[shortest[k]]!=0){k++;shortest[k]=pre[shortest[k-1]];}k++;shortest[k]=0;for(j=k;j>0;j--)printf("%d-->",shortest[j]);printf("%d\n",shortest[0]);}return 0;}/*70 1 60 2 50 3 51 4 -12 1 -22 4 13 2 -23 5 -14 6 35 6 3-1 -1 -1*/
- 最短路之bellman-ford
- 最短路 bellman-ford
- 最短路~bellman-ford
- 最短路-Bellman-Ford
- 最短路之Bellman-Ford算法
- 最短路之bellman-ford HDU 1874
- 最短路之Bellman-Ford算法
- bellman ford最短路算法
- 最短路--Bellman-Ford算法
- bellman-ford算法 最短路
- Bellman-Ford(最短路)
- Bellman-ford最短路算法
- 图论浅析--最短路之Bellman-Ford
- POJ 1860(最短路之Bellman-Ford)
- 图论最短路之bellman-ford
- poj 2240 Arbitrage(最短路+Bellman-Ford)
- 旧代码 - 最短路 Bellman Ford
- poj1860_最短路bellman Ford算法应用
- Ubuntu下gcc安装及使用
- vmTools 在VMware中的安装
- 详解linux源码包安装过程
- ubuntu安装deb,rpm安装包方法
- 说话就是生产力
- 最短路之bellman-ford
- 0-1背包问题与完全背包问题C++实现 动态规划
- 元旦随想
- springAOP——代理对象的产生及方法调用
- android:layout_width="match_parent"
- Yii 的登录流程
- Yii框架执行流程
- 关于HTML5的11个让人难以接受的事实
- JAVA基础之理解JNI原理