10/21/2018 Bellman-Ford 算法

本文探讨了在存在负权边的图中寻找最短路径的问题。阐述了当图中存在负权环时,最短路径可能不存在的概念,并介绍了贝尔曼-福特算法,一种能够检测负权环并找到所有顶点最短路径的算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Background:

当负权存在时,最短路不一定存在。如果最短路存在,一定存在一个不含环的最短路。

理由如下:在边权可正可负的图中,环有零环、正环和负环三种。如果包含零环或正环,去掉以后路径不会变长;如果包含负环,则意味着最短路不存在。(路径可以一直在负环中循环,则权值会无限小)

既然不含环,则最短路最多只经过(不算起点)n - 1个结点,可以通过n - 1 轮松弛操作得到。代码如下(起点为0):

for (int i = 0; i < n; i++) d[i] = INF;
d[0] = 0;
for (int k = 0; k < n - 1; k++) {
	int x = u[i], y = v[i];
	if (d[x] < INF) d[y] = min(din[y], d[x] + w[i]);
}

Algorithm Details: 

Input: Graph and a source vertex src

Output: Shortest distance to all vertices from src. If there is a negative weight cycle, then the shortest distances are not calculated, the negative weight cycle is reported. 

1) This step initializes distances from source to all vertices as infinite and distance to the source itself is 0. Create an array dist[] of size |V| with all values as infinite except dist[src] where src is the source vertex

2) This step calculates the shortest distance Do following |V| - 1 times where |V| is the number of vertices in the given graph.

    a) Do following for each edge u-v

      if dist[v] > dist[u] + weight of edge uv, then update dist[v]

        dist[v] = dist[u] + weight of edge u

3) This step reports if there is a negative weight cycle in the graph. Do following for each u-v

    if dist[v] > dist[u] + weight of edge uv, then "Graph contains negative cycle"

    The idea of step 3 is, step 2 guarantees the shortest distances if the graph doesn't contain negative weight cycle. If we iterate through all edges one more time and get a shorter path for any vertex, then there is a negative weight cycle.

 

Idea: Like other Dynamic Programming Problems, the algorithm calculates shortest paths in bottom-up manner. It first calculates the shortest distances which have at most one edge in the path. Then, it calculates shortest paths with at most 2 edges, and so on. After the ith iteration of the outer loop, the shortest paths with at most i edges  are calculated. There can be maximum |V| - 1 edges in any simple path, that is why the outer loop runs |V| - 1 times. The idea is, assuming that there is no negative weight cycle, if have calculated shortest paths with at most i edges, then an iteration over all edges guarantees to give the shortest path with at-most (i + 1) edges. 


class Graph3 {
    class Edge {
        int src, dest, weight;
        Edge() {
            src = dest = weight = 0;
        }
    };
    
    int V, E;
    Edge edge[];
     Graph3(int v, int e) {
        V = v;
        E = e;
        edge = new Edge[e];
        for (int i = 0; i < e; i++) {
            edge[i] = new Edge();
        }
    }
    void BellmanFord(Graph3 graph, int src) {
         int V = graph.V, E = graph.E;
         int dist[] = new int[V];
         //Step1: initialize distances from src to all other
        // vertices as infinite
         for (int i = 0; i < V; i++) {
             dist[i] = Integer.MAX_VALUE;
         }
         dist[src] = 0;
         
         //Step2: Relax all edges |V| - 1 time. A simple 
         //shortest path from src to any other vertex can 
         //have at-most |V| - 1 edges
        for (int i = 1; i < V; i++) {
            for (int j = 0; j < E; j++) {
                int u = graph.edge[j].src;
                int v = graph.edge[j].dest;
                int weight = graph.edge[j].weight;
                if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) 
                    dist[v] = dist[u] + weight;
            }
        }
        //Step3: check for negative-weight cycles. The above steps guarantees shortest distances
        //if graph doesn't contain negative weight cycle. If we get a shorter path, then there is 
        //a cycle.
        for (int j = 0; j < E; j++) {
            int u = graph.edge[j].src;
            int v = graph.edge[j].dest;
            int weight = graph.edge[j].weight;
            if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) 
                System.out.println("Graph contains negative weight cycle");
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值