最短路之贝尔曼(bellmanford)算法

贝尔曼(bellmanford)算法:node

大意:分为两步:1,对各边进行松弛操做,即更新最短距离 2,判断是否产生回路web

 

Bellman-Ford算法的流程以下:
给定图G(V, E)(其中V、E分别为图G的顶点集与边集),源点s,
数组Distant[i]记录从源点s到顶点i的路径长度,初始化数组Distant[n]为, Distant[s]为0;
算法

 如下操做循环执行至多n-1次,n为顶点数:
对于每一条边e(u, v),若是Distant[u] + w(u, v)< Distant[v],则另Distant[v] = Distant[u]+w(u, v)。w(u, v)为边e(u,v)的权值;
若上述操做没有对Distant进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。不然执行下次循环;
为了检测图中是否存在负环路,即权值之和小于0的环路。对于每一条边e(u, v),若是存在Distant[u] + w(u, v)< Distant[v]的边,则图中存在负环路,便是说改图没法求出单源最短路径。不然数组Distant[n]中记录的就是源点s到各顶点的最短路径长度。
可知, Bellman-Ford算法 寻找单源最短路径的时间复杂度为O(V*E).
数组

 

例子:ui

Descriptionthis

While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of FJ's farms comprises N (1 ≤ N ≤ 500) fields conveniently numbered 1..N, M (1 ≤ M ≤ 2500) paths, and W (1 ≤ W ≤ 200) wormholes.spa

As FJ is an avid time-traveling fan, he wants to do the following: start at some field, travel through some paths and wormholes, and return to the starting field a time before his initial departure. Perhaps he will be able to meet himself :) .code

To help FJ find out whether this is possible or not, he will supply you with complete maps to F (1 ≤ F ≤ 5) of his farms. No paths will take longer than 10,000 seconds to travel and no wormhole can bring FJ back in time by more than 10,000 seconds.orm

Inputip

Line 1: A single integer, F. F farm descriptions follow.
Line 1 of each farm: Three space-separated integers respectively: N, M, and W
Lines 2..M+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: a bidirectional path between S and E that requires T seconds to traverse. Two fields might be connected by more than one path.
Lines M+2..M+W+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: A one way path from S to E that also moves the traveler back T seconds.

Output

Lines 1..F: For each farm, output "YES" if FJ can achieve his goal, otherwise output "NO" (do not include the quotes).

Sample Input

2 3 3 1 1 2 2 1 3 4 2 3 1 3 1 3 3 2 1 1 2 3 2 3 4 3 1 8

Sample Output

NO YES

题目大意:

    FJ童鞋家的农田里面有若干个虫洞,有一些虫洞是相连的,能够消耗一些时间爬过去(无向)。还有一些虫洞比较特殊,从一头爬到那一头以后时间会退后一些(有向)

    FJ但愿经过爬虫洞(?)来时时间退后,从而能看到另一个本身。根据输入的虫洞信息来判断是否能够实现FJ的愿望。

code:

  #include<stdio.h>
#define inf 999999
struct node
{
    int u,v,w;
} edge[6000];
int dis[505];
int n,m,w,in;
void add(int u,int v,int c)
{
    in++;
    edge[in].u=u;
    edge[in].v=v;
    edge[in].w=c;
}
int bellman()
{
    int u,v,w,i,j,flag;
    for(i=1; i<=n; i++)//初始化
    {
        dis[i]=inf;
    }
    dis[1]=0;
    flag=0;
    for(i=1; i<=n; i++)//边的松弛
    {
        for(j=1; j<=in; j++)
        {          

             if(dis[edge[j].v]>dis[edge[j].u]+edge[j].w)
            {
                dis[edge[j].v]=dis[edge[j].u]+edge[j].w;
            }
        }
    }
    for(i=1; i<=in; i++)//判断是否有回路
        if(dis[edge[i].v]>dis[edge[i].u]+edge[i].w)
            return 1;
    return 0;
}
int main()
{
    int i,j,t,u,v,c;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&w);
        in=0;
        for(i=0; i<m; i++)
        {
            scanf("%d%d%d",&u,&v,&c);
            add(u,v,c);
            add(v,u,c);
        }
        for(i=0; i<w; i++)
        {
            scanf("%d%d%d",&u,&v,&c);
            add(u,v,-1*c);
        }
        if(bellman())
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}
Dijkstra算法和Bellman算法思想有很大的区别:
      Dijkstra算法在求解过程当中,源点到集合S内各顶点的最短路径一旦求出,则以后不变了,修改的仅仅是源点到T集合中各顶点的最短路径长度。Bellman算法在求解过程当中,每次循环都要修改全部顶点的dist[],也就是说源点到各顶点最短路径长度一直要到Bellman算法结束才肯定下来。
若是存在从源点可达的负权值回路,则最短路径不存在,由于能够重复走这个回路,使得路径无穷小。  
   

 做为一种单源最短路径算法,Bellman-Ford对于有向图和无向图都能适用,它还有一个Dijkstra算法没法具有的特色,那就是对含负权图的最短路径搜索。每i轮对边的遍历以后,只要不存在负权回路,Bellman-Ford算法均可以保证得到距离源点i条边的点的最短路径。由于最短路径的最大长度不会超过n条边,n为节点的数目。因此n次遍历后全部的节点一定都能找到最短路径。若是n次后还能够继续松弛,则代表该图存在负权回路,能够对代码稍做修改来计算负权环的大小。

相关文章
相关标签/搜索