图的最短路径算法 Bellman-Ford算法

Bellman-Ford算法由美国数学家理查德•贝尔曼(Richard Bellman, 动态规划的提出者)和小莱斯特•福特(Lester Ford)发明。

适用范围:
- 有向图,无向图(需把edge重复2遍);
即对于边w(u, v),存储2遍: w(u,v), w(v,u);
- 适用于从图中某个固定点,到其他点的最短路径求解;

算法大致说明:
1. 初始化所有点,用dis[i]数组存储root点到i点的最短路径;
2. dis[root]为0,其他的dis[i]用最大值初始化;
3. 遍历所有的边w(u,v);如果dis[u]+w(uv)的值小于当前的dis[v],则替换之;
4. pre[i] 保存访问的路径;

 

#include<iostream>  
#include<cstdio>  
using namespace std;

#define MAX 0x3f3f3f3f  
#define N 1010  
int nodenum, edgenum, original; //点,边,起点  

typedef struct Edge //
{
    int u, v;
    int cost;
}Edge;

Edge edge[N];
int dis[N], pre[N];

bool Bellman_Ford()
{
    for (int i = 1; i <= nodenum; ++i) //初始化  
        dis[i] = (i == original ? 0 : MAX);
    for (int i = 1; i <= nodenum - 1; ++i)  
    for (int j = 1; j <= edgenum * 2; ++j)
    {
        if (dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)  
        {
            dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;
            pre[edge[j].v] = edge[j].u;
        }
    }
    bool flag = 1; //判断是否含有负权回路  
    for (int i = 1; i <= edgenum*2; ++i)
        if (dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)
        {
            flag = 0;
            break;
        }
    return flag;
}

void print_path(int root) //打印最短路的路径(反向)  
{
    while (root != pre[root]) //前驱  
    {
        printf("%d-->", root);
        root = pre[root];
    }
    if (root == pre[root])
        printf("%d\n", root);
}

int main()
{
    scanf("%d%d%d", &nodenum, &edgenum, &original);
    pre[original] = original;
    for (int i = 1; i <= edgenum; ++i)
    {
        scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);
        edge[edgenum + i].u = edge[i].v;
        edge[edgenum + i].v = edge[i].u;
        edge[edgenum + i].cost = edge[i].cost;
    }
    if (Bellman_Ford())
        for (int i = 1; i <= nodenum; ++i) //每个点最短路  
        {
            printf("path from %d to %d is: %d\n", original, i, dis[i]);
            printf("Path:");
            print_path(i);
        }
    else
        printf("have negative circle\n");

    system("pause");
    return 0;
}

 

一个测试用例:

6 8 6 
6 5 100
6 4 30
6 2 10
4 5 60
4 3 20
3 5 10
2 3 50
1 2 5
posted @ 2015-08-31 18:03  Bouygues  阅读(672)  评论(0编辑  收藏  举报