ACM_Bellman-ford算法

Bellman_ford算法:也是求单源最短路径,它与Dijkstra算法的区别是,它可以检查是否有负权值边的存在;如果有负权值边的话,是不存在最短路径的,因为一个数+负数,一定会更小,所以dis数组会不断更新;

#include
#include
using namespace std;
#define INF 9999999
struct node
{
    int u,v,w;
};//用结构体来保存边,u,v,w分别为边的端点和权值
struct node a[109];
int n,m,dis[109],t;//n个点,m条边,dis[i]保存的是源点s到i的最短路径
bool bellman_ford(int s)//源点s
{
    int i,j;
    bool flag = true;//bool型变量,用来判断是否有负权值的边
    dis[s] = 0;//源点到源点的距离为0,这条语句非常的关键,就是因为它,下面的
    //dis数组才会更新
    for (i = 1; i <= n-1; ++i)//最坏的情况,内层for循环,假设每次循环完只会更新
        //一条边,那么n个点,源点到其他点最多需要n-1条边,所以循环n-1次就OK
    {
        for (j = 1; j <= 2*m; ++j)//m条边,因为是无向图,所以是2m
        {
            if (dis[a[j].u] > dis[a[j].v] + a[j].w)//正是因为dis[s]=0,dis数组才会更新
                dis[a[j].u] = dis[a[j].v] + a[j].w;
        }
    }
    for (j = 1; j <= 2*m; ++j)
    {
        if (dis[a[j].u] > dis[a[j].v] + a[j].w)//原来的最短路径+负数,一定会更小,也就是说,如果
            //会更新,那么说明有负权值的边存在
        {
            flag = false;
            break;
        }
    }
    return flag;
}
int main()
{
    int i,j,s,d,u,v,w;
    while (~scanf("%d%d",&n,&m))
    {
        for (i = 1; i <= n; ++i)
            dis[i] = INF;
        j = 1;
        t = m;
        while (t--)
        {
            scanf("%d%d%d",&u,&v,&w);
            a[j].u = u;
            a[j].v = v;
            a[j++].w = w;
            a[j].u = v;
            a[j].v = u;
            a[j++].w = w;
        }//因为是无向图,边正反存
        scanf("%d%d",&s,&d);//s是源点,d是终点
        if (bellman_ford(s))
            printf("%d\n",dis[d]);
        else
            printf("sorry\n");
    }
    return 0;
}
/*
该算法是从边出发的!边更新了,也就是到点的距离更新了,然后感觉也是用点来更新点的
给两组样例吧
(1)                     (2)
5 7                             4 4
1 2 100                         1 2 -9
1 5 10                          2 3 1
1 3 30                          3 4 2
2 3 60                          4 1 3
2 4 10                          1 2
3 4 60                         (sorry)
4 5 50
1 4
(60)
根据样例画画图就很好理解!
*/


你可能感兴趣的:(ACM_算法)