单源最短路径:固定一个点,求它到其他所有点的最短路问题。
记从起点s出发到顶点i的最短距离为d[i]。则下列等式成立:
d[i]=min{d[j]+(从j到i的边权值)|e=(j,i)属于E}
记当前到顶点i的最短路长度为d[i],并设初值d[s]=0,d[i]=INF,再不断使用这条递推关系式更新d的值,就可以算出新的d。前提是图中不存在负圈。结束之后的d就是所求的最短距离。
测试数据:
6 9
0 1 1
0 2 12
1 2 9
1 3 3
2 4 5
3 2 4
3 4 13
3 5 15
4 5 4
期待输出结果:
0 1 8 4 13 17
代码如下:
//Bellman_Ford算法
#include<iostream>
#include<algorithm>
#define INF 99999
#define MAX_E 100
#define MAX_V 50
using namespace std;
//从顶点from指向顶点to的权值为cost的边
struct edge{
int from,to,cost;
};
//邻接表
edge es[MAX_E]; //边
int d[MAX_V]; //最短距离
int V,E; //V是顶点数、E是边数
//求解从顶点s出发到所有点的最短距离
void shortest_path(int s)
{
for(int i=0;i<V;i++)
d[i]=INF;
d[s]=0;
// cout << "1\n";
while(true)
{
// cout << "2\n";
bool update=false;
for(int i=0;i<E;i++)
{
edge e=es[i];
if(d[e.from]!=INF&&d[e.to]>d[e.from]+e.cost)
{
d[e.to]=d[e.from]+e.cost;
update=true;
}
}
if(!update)
break;
}
}
int main()
{
cin >> V >> E;
for(int i=0;i<E;i++)
cin >> es[i].from >> es[i].to >> es[i].cost;
shortest_path(0);
for(int i=0;i<V;i++)
{
cout << d[i] << endl;
}
return 0;
}
如果图中不存在从s可达的负圈,那么最短路不会经过同一个顶点两次。检查负圈的函数:
bool find_negative_loop()
{
for(int i=0;i<V;i++)
d[i]=0;
for(int i=0;i<V;i++)
{
for(int j=0;j<E;j++)
{
edge e=es[j];
if(d[e.to]>d[e.from]+e.cost)
{
d[e.to]=d[e.from]+e.cost;
if(i==V-1)
return true;
}
}
}
return false;
}