从源列表和目的地列表中查找有向加权图中的最短路径

卢多维科·洛雷蒂

首先,我的 Graph 包含负权重,所以我不能使用 Dijkstra 算法。

我尝试使用和编辑一种 Floyd-Warshall 算法,但它仅在某些情况下有用。也许我必须使用 Bellman-Ford 算法的编辑版本,但我找不到方法..

<EDIT>

我无法找到一种方法来获得正确的输出,而不是找到最短路径,因为我能够做到这一点,而是在此输入中获得正确的输出。(查看绘图并将其与输出进行比较,您可以看到它是不同的。例如:

2 -> 5     -4    2 -> 1 -> 3 -> 4 -> 5

距离 -4 是不正确的,在平局中是 -2,而在另一个输出中,输入有点不同,如下面的帖子所述,一切都是正确的。

</EDIT>

这是我的输入(1)文件:

6 9
2 3
0 1 -2
0 2 1
2 1 -3
1 3 2
2 3 3
2 5 1
5 3 1
3 4 1
4 5 -3

其中6是节点的数量,9是边缘的数量,23分别是源和目的地(0<=sourceNodes<=23<=destinationsNodes<=5其中I必须计算的最短路径)。所以,在这个输入文件中,我的代码给了我这个输出,如果我们看到我为你做的画,那就错了。

来自输入 1 的图形

虽然输出是:

pairs     dist     path
0 -> 3    -1     0 -> 1 -> 3
0 -> 4     0     0 -> 1 -> 3 -> 4
0 -> 5    -3     0 -> 1 -> 3 -> 4 -> 5
1 -> 3     1     1 -> 3
1 -> 4     2     1 -> 3 -> 4
1 -> 5    -1     1 -> 3 -> 4 -> 5
2 -> 3    -2     2 -> 1 -> 3
2 -> 4    -1     2 -> 1 -> 3 -> 4
2 -> 5    -4     2 -> 1 -> 3 -> 4 -> 5

这是我的代码:

import java.util.*;
import java.lang.*;
import java.io.*;

public class Esercizio3 {

public static void main(String args[]) throws IOException {
    try {
        Scanner scan = new Scanner(new File("/myFiles/Input2Es3.txt"));
        int totNodi = scan.nextInt();
        System.out.println("totNodi: "+totNodi);
        int totArchi = scan.nextInt();
        System.out.println("totArchi: "+totArchi);
        // ingressi
        int nIngressi = scan.nextInt();
        System.out.println("nIngressi: "+nIngressi);
        int[] ingresso = new int[nIngressi+1];
        for (int i=0; i<=nIngressi; i++) {
            ingresso[i] = i;
            System.out.println("> INGRESSO: "+ingresso[i]);
        }
        // uscite
        int startUscite = scan.nextInt();
        //        int endUscite = totNodi-1;
        int nUscite = totNodi-startUscite;
        System.out.println("nUscite: "+nUscite);
        int[] uscita = new int[nUscite];
        for (int i=startUscite; i<totNodi; i++) {
            int index = i-startUscite;
            uscita[index] = i;
            System.out.println("> USCITA: "+uscita[index]);
        }
        // archi
        int V = totNodi;
        int E = totArchi;
        int[][] weights = new int[totArchi][3];
        for (int i=0; i<totArchi; i++) {
            weights[i][0] = scan.nextInt();
            weights[i][1] = scan.nextInt();
            weights[i][2] = scan.nextInt();
            System.out.println(weights[i][0] + " - " + weights[i][1] + " - " + weights[i][2]);
        }

        floydWarshall(weights,totNodi,ingresso,uscita);


    } catch (FileNotFoundException ex) {
        System.out.println(ex);
    }
}

static void floydWarshall(int[][] weights, int numVertices, int[] ingresso, int[] uscita) throws IOException {

    double[][] dist = new double[numVertices][numVertices];
    for (double[] row : dist)
        Arrays.fill(row, Double.POSITIVE_INFINITY);

    for (int[] w : weights)
        dist[w[0]][w[1]] = w[2];

    int[][] next = new int[numVertices][numVertices];
    for (int i = 0; i < next.length; i++) {
        for (int j = 0; j < next.length; j++)
            if (i != j)
                next[i][j] = j + 1;
    }

    for (int k = 0; k < numVertices; k++)
        for (int i = 0; i < numVertices; i++)
            for (int j = 0; j < numVertices; j++)
                if (dist[i][k] + dist[k][j] < dist[i][j]) {
                    dist[i][j] = dist[i][k] + dist[k][j];
                    next[i][j] = next[i][k];
                }

    printResult(dist, next, ingresso, uscita);
}

static void printResult(double[][] dist, int[][] next, int[] ingresso, int[] uscita) throws IOException {
    BufferedWriter writer = new BufferedWriter(new FileWriter("myoutputfile.txt"));

    double distMin =  Double.POSITIVE_INFINITY;
    int indexI = 0;
    int indexJ = 0;
    for (int i = 0; i < next.length; i++) {
        for (int j = 0; j < next.length; j++) {
            if ((i != j) && (dist[i][j]!=Double.POSITIVE_INFINITY) && (i>=ingresso[0] && i<=ingresso[ingresso.length-1]) && (j>=uscita[0] && j<=uscita[uscita.length-1])) {
                int u = i + 1;
                int v = j + 1;
                String path = format("%d -> %d    %2d     %s", i, j, (int) dist[i][j], i);
                do {
                    u = next[u-1][v-1];
                    path += " -> " + (u-1);
                } while (u != v);
                System.out.println(path);



                if(distMin > dist[i][j]) {
                    distMin = dist[i][j];
                }

            }
        }
    }
}

}

我该如何解决这个问题?因为使用另一个输入它可以完美运行:

运行的输入(2) (它与第一个类似,但在最后一个 raw 中权重不同)

6 9
2 3
0 1 -2
0 2 1
2 1 -3
1 3 2
2 3 3
2 5 1
5 3 1
3 4 1
4 5 1

输出完美:

0 -> 3     0     0 -> 1 -> 3
0 -> 4     1     0 -> 1 -> 3 -> 4
0 -> 5     2     0 -> 2 -> 5
1 -> 3     2     1 -> 3
1 -> 4     3     1 -> 3 -> 4
1 -> 5     4     1 -> 3 -> 4 -> 5
2 -> 3    -1     2 -> 1 -> 3
2 -> 4     0     2 -> 1 -> 3 -> 4
2 -> 5     1     2 -> 5

The only thing I know is that for the first input the output should be -1, while for the last input the output should be 2 -> 1 -> 3 which is the path with the shortest distance between a source node and a destination node (and it's correct).

Thank you

Mohaimin66

Firstly if there is a negative cycle then we can't find a shortest path. It is easy to visualize that. Cause if we repeatedly traverse the negative cycle then the cost will decrease for every traversal. As a result we will find infinitely decreasing value of our path.

Well, to avoid this drawback we use Bellman-Ford's algorithm. Which detects whether a graph contains a negative cycle or not. I am assuming you know Bellman-Ford's and Dijkstra's Algorithm and used to with the term "Relaxation".

Now we will follow an approach known as Johnson's algorithm:

  • We will add an extra vertex X and connect it to all the other vertices of the graph and the edges will all be of cost 0.
  • Taking the new vertex X as source, we will apply Bellman-Ford's algorithm. Which will find the shortest path of all the edges from the source in a total of (n-1) iterations, where n is total number of vertices including X. We will take an extra iteration, from the same source and it will perform differently in two different cases.

    1. Negative cycle present: Relaxation will be seen again to happen. It means there is a negative cycle and we can't have a shortest path in the graph as I explained above. So, our program should terminate.

    2. Negative cycle not present: No relaxation will take place and we got the shortest path of all vertices from X. We are ready to go!

  • We will reweight the edges of the original graph using the shortest path from the Bellman-Ford's algorithm. If u and v has a edge in main graph with cost w(u,v) and shortest paths of u and v from X are h(u) and h(v) respectively, then new weight nw(u,v)= w(u,v)+h(u)-h(v).

Now Dijkstra's algorithm from your selected source should find the shortest path to all vertices on the reweighted graph which is also the shortest path of the original graph.

如果您还感到困惑,请查看Wikipedia 上的Johnson 算法

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

BFS 查找源 S 和多个目的地之间的所有最短路径

最短路径算法:多源,最接近目的地

源和目标网络列表x的最短路径

在O(V + E)时间内找到无向加权图中从源到目标的最短路径

加权有向图最短路径的最佳方法

在加权图中找到最短路径

在循环加权图中寻找最短路径

加权图中最短路径的数量

有向无环图中小度的最短路径

图中每个节点与列表中元素之间的最短路径

无向加权图中2个顶点之间的最短路径

计算无向加权图中一组顶点之间的最短路径

具有已知起始节点并访问所有节点而无需返回起始节点的完整加权无向图中的最短路径

列表列表之间的最短路径

如何使用SWI Prolog为加权有向图找到唯一的最短路径?

如何使用NetworkX获得加权图中的最短路径?

用加权顶点计算图中的最短路径

遗传算法 - 加权图中的最短路径

为了找到最短路径,如何在有向加权图中将一个边精确设置为零?

图形项的依赖项列表中的最短路径

将最短路径中的所有节点作为对象列表返回

常见来源和目的地列表

给定邻接列表有向图,如何仅获得两个节点之间的最短路径?

最短路径查询返回空列表

完整有向图中访问所有节点的最短路径

具有负长度循环的有向图中的最短路径

有向权重图中具有设定权重数量的最短路径

如何在图中找到两个顶点不相交的路径,两条路径具有相同的源但不同的目的地?

基于源目的地字典的源路径计算