Bellman变形得来的SPFA最短算法(不能含负环);Floyd求两点间最短路,求有向图的闭包;
2010-06-17 10:26
357 查看
#include <iostream> #include <queue> using namespace std; const int MAXN=100; /*********************************/ * SPFA算法需要的空间分配 /*********************************/ queue<int> q; bool inq[MAXN]; /*********************************/ * 构造稀疏矩阵的邻接表 表示法 * u,v:边的端点 * first:表结点 * next:弧结点 * w: 边的权值 * n:顶点数目 m:边数目 /*********************************/ int u[MAXN]; int v[MAXN]; int w[MAXN]; int first[MAXN]; int next[MAXN]; int n,m; /*********************************/ * 读入图到邻接表中 (无向图) /*********************************/ void readG1() { memset(first,-1,sizeof(first)); cin>>n>>m; int i,j; for(i=0,j=0;i<m;++i) { int a,b,c; cin>>a>>b>>c; u[j]=a; w[j]=c; next[j]=first[u[j]]; first[u[j]]=j; v[j++]=b; u[j]=b; v[j]=a; w[j]=c; next[j]=first[u[j]]; first[u[j]]=j; v[j++]=a; } } /*********************************/ * 读入图到邻接表中 (有向图) /*********************************/ void readG2() { memset(first,-1,sizeof(first)); cin>>n>>m; int i; for(i=0;i<m;++i) { int a,b,c; cin>>a>>b>>c; u[i]=a; v[i]=b; w[i]=c; next[i]=first[u[i]]; first[u[i]]=i; } } /*********************************/ * 普通队列+标记数组=SPFA * 实际就是Bellman的一个小变形得来的 /*********************************/ int d[MAXN]; void BellmanFord_SPFA() { // 顶点0作为源点 for(int i=0;i<n;++i) { d[i]=i==0? 0:MAXN; } memset(inq,0,sizeof(inq)); q.push(0); while(!q.empty()) { int x=q.front(); q.pop(); inq[x]=false; for(int e=first[x];e!=-1;e=next[e]) { if(d[v[e]]>d[x]+w[e]) { d[v[e]]=d[x]+w[e]; if(!inq[v[e]]) { inq[v[e]]=true; q.push(v[e]); } } } } } /*********************************/ * Floyd 算法的实现 (有向图) * Floyd 实现有向图的闭包 * d[i][j] 表示i到j的最短路径 * c[i][j] =1表示i到j可以连通,=0表示不可连通 /*********************************/ int dd[MAXN][MAXN]; int c[MAXN][MAXN]; void Floyd() { //预处理 for(int i=0;i<n;++i) { for(int k=0;k<n;++k) { dd[i][k]= i==k ? 0:MAXN; c[i][k]= i==k ? 1:0; } for(int j=first[i];j!=-1;j=next[j]) { dd[i][v[j]]=w[j]; c[i][v[j]]=1; } } //Floyd两点间最短路算法 for(int k=0;k<n;++k) { for(int i=0;i<n;++i) { for(int j=0;j<n;++j) { if(dd[i][k]<MAXN&&dd[k][j]<MAXN) { if(dd[i][j]>dd[i][k]+dd[k][j]) { dd[i][j]=dd[i][k]+dd[k][j]; } } c[i][j]=c[i][j]||(c[i][k]&&c[k][j]); } } } } int main() { /*测试Floyd算法 4 5 0 1 1 0 2 3 0 3 3 1 3 1 1 2 1 */ readG2(); Floyd(); for(int i=0;i<n;++i) { for(int j=0;j<n;++j) { cout<<i<<","<<j<<"----"<<dd[i][j]<<"-----"<<c[i][j]<<endl; } } /* SPFA测试:0为源点 */ BellmanFord_SPFA(); for(int i=0;i<n;++i) { cout<<i<<"--0 :"<<d[i]<<endl; } return 0; }
依旧采取静态数组邻接表 来构图, 这样使用非常方便, 只要在邻接表内的边都是存在的边, 而没有的边均是不通的边, 输入起来很方便, 使用时候也很方便.
Bellman变形得到的就是SPFA算法, 复杂度比bellman更低一些,比迪克拉斯算法适用范围更广,边权可以有负值, 但是不能带负环,否则绕着负环无限走下去,总能变得越来越小.
这些最短路算法都是使用了松弛原理, 只是松弛时又做了一些小变化.
SPFA : 初始化源点的d[]=0,其他的d[]=INF.
源点入队, 每次取队头出队列, 标记它不在队列内, 如果可以更新它所关联的端点, 并且端点不在队列内,则加入队列.
这样,每个端点都可能重复进入队列,但是经过有限次松弛, 总会使所有的端点的最短路径都无法再次更新. Dij算法区别于使用了
优先队列, 每次出队的结点已经完美,无需再次进入,而这里使用的是普通队列. Dij只允许正权图使用.
还有Floyd算法, 可以求任意两点间最短路径, O(n3)复杂度, 写起来很简单, 需要做一些初始化.
d[][]=INF。
然后修正以下内容:
d[i][i]=0,c[i][i]=1. 即自身可与自身连通,到自身路径是0.
d[i][j]=w[i][j]
然后可以使用算法了.
相关文章推荐
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 带权最短路 Dijkstra, SPFA, Bellman-Ford, ASP, Floyd-Warshall 算法分析
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 最短路径:Dijkstra,Bellman,SPFA,Floyd该算法的实施
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 模板--Floyd Dijkstra Bellman-Ford spfa 四种最短路经典算法
- 最短路径算法 模板_Dijkstra_Bellman.ford_Floyd_spfa
- 带权最短路 Dijkstra, SPFA, Bellman-Ford, ASP, Floyd-Warshall 算法分析
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 四种最短路径算法(Dijkstra,Floyd,Bellman-ford&&spfa)
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较(转)
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- Floyd Dijkstra Bellman-Ford spfa 四种最短路经典算法汇总 HDU 2544为例
- 带权最短路 Dijkstra, SPFA, Bellman-Ford, ASP, Floyd-Warshall 算法分析
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
- 几大最短路径算法比较(Floyd & Dijkstra & Bellman-Ford & SPFA)
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较