单源最短路径问题
对于给定的图G(V,E),求出从给定的源顶点s到图中其他顶点v 属于 V的最短路径。
Bellman-Ford算法
松弛操作
所谓松弛操作,是指对于给定的两个顶点u和v,已知源顶点s到v的距离为d[v],u与v距离为w[u][v],若有d[v]>d[u]+w[u][v],则修改源顶点s到v的最短距离d[v】为d[u]+w[u][v],同时修改结点v的父节点c[v]为u。
松弛操作的代码实现:
void relax(int d[n],int c[n],int u,int v){
if(d[v]>d[u]+w[u][v]){
d[v] = d[u]+w[u][v];
c[v] = u;
}
}
算法实现
了解了松弛操作之后,就很容易理解Bellman-Ford算法了。我们知道,最短路径应该是不包含环路的,因此对于求得的最短路径而言,最多有|V|-1条边。根据这一想法,我们只需要对图的每一对顶点进行|V|-1次松弛操作就可以求得最短路径。
代码实现
#include <stdio.h>
#define INF 1<<20
#define s 0
#define t 1
#define x 2
#define y 3
#define z 4
const int n = 5;
int w[n][n] =
{ {0,6,INF,7,INF},
{INF,0,5,8,-4},
{INF,-2,0,INF,INF},
{INF,INF,-3,0,9},
{2,INF,7,INF,0}
};
//图的初始化
void init(int d[n],int c[n]){
for(int i=0;i<n;i++){
d[i] = INF;
c[i] = INF;
}
d[0] = 0;
}
//松弛操作
//d[i]表示最短距离,c[i]表示结点i的父节点
void relax(int d[n],int c[n],int u,int v){
if(d[v]>d[u]+w[u][v]){
d[v] = d[u]+w[u][v];
c[v] = u;
}
}
int bellman (int d[n],int c[n]){
init(d,c);
for(int i=1;i<n;i++){
for(int j=0;j<n;j++){
for(int k=0;k<n;k++){
relax(d,c,j,k);
}
}
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(d[i]>d[j]+w[j][i])
return 0;
}
}
return 1;
}
//递归打印处路径
void print(int d[n],int c[n],int m){
if(m==s){
printf("%c ",'s');
}
else{
print(d,c,c[m]);
if(m==t) printf("%c ",'t');
if(m==x) printf("%c ",'x');
if(m==y) printf("%c ",'y');
if(m==z) printf("%c ",'z');
}
}
int main(void){
int d[n];
int c[n];
int flag = bellman(d,c);
if(flag==1){
for(int i=0;i<n;i++){
printf("%d ",d[i]);
}
printf("\n");
for(int i=1;i<n;i++){
print(d,c,i);
printf("\n");
}
}
}