如何在Floyd-Warshall算法中输出最短路径?

时间:2010-12-24 13:22:42

标签: c# algorithm floyd-warshall

我正在尝试实现Floyd-Warshall算法(所有对最短路径)。在下面的代码中,当我输入一些数字时,它将最后一个数字作为输入。我知道代码不完整。

现在我该怎么做才能为每个i和j打印最短路径?或者你建议我做些什么来完成这段代码。感谢。

private void button10_Click(object sender, EventArgs e)
{

    string ab = textBox11.Text;
    int matrixDimention = Convert.ToInt32(ab);
    int[,] intValues = new int[matrixDimention, matrixDimention];
    string[] splitValues = textBox9.Text.Split(',');
    for (int i = 0; i < splitValues.Length; i++)
        intValues[i / (matrixDimention), i % (matrixDimention)] =    Convert.ToInt32(splitValues[i]);
    string displayString = "";
    for (int inner = 0; inner < intValues.GetLength(0); inner++)
    {
        for (int outer = 0; outer < intValues.GetLength(0); outer++)
            displayString += String.Format("{0}\t", intValues[inner, outer]);
        displayString += Environment.NewLine;
    }
    int n = (int)Math.Pow(matrixDimention, 2);
    string strn = n.ToString();

    MessageBox.Show("matrix"+strn+ "in" + strn + "is\n\n\n" +displayString);
////before this line i wrote the codes to get the numbers that user enter in textbox and put it in an 2d array
    for (int k = 1; k < n+1; k++)

        for (int i = 1; i < n+1; i++)

            for (int j = 1; j < n+1; j++)

                if (intValues[i, j] > intValues[i, k] + intValues[k, j])
                {
                    intValues[i, j] = intValues[i, k] + intValues[k, j];
                    string str_intvalues = intValues[i, j].ToString();
                    MessageBox.Show("Shortest Path from i to j is: " + str_intvalues);

                }
                else
                {
                    string str_intvalues = intValues[i, j].ToString();
                    MessageBox.Show("Shortest Path from i to j is: " + str_intvalues);
                }
}

2 个答案:

答案 0 :(得分:7)

要在同一页面上,让我先向您展示Floyd-Warshall算法:

让我们有一个图表,由矩阵D描述,其中D[i][j]是边(i -> j) 的长度(从图的顶点索引i到索引j)的顶点

矩阵D的大小为N * N,其中N是图中顶点的总数,因为我们可以通过将每个图的顶点相互连接来达到路径的最大值。

我们还需要矩阵R,我们将存储最短路径(R[i][j]包含最短路径中下一个顶点的索引,从顶点i开始到结束于顶点j)。

矩阵R的大小与D相同。

Floyd-Warshall算法执行以下步骤:

  1. 使用边缘的末端顶点初始化图形中任意两对或顶点之间所有路径的矩阵(这很重要,因为此值将用于路径重建) < / p>

  2. 对于每对连接的顶点(读取:对于每个边(u -> v)uv,找到顶点,形成它们之间的最短路径:如果顶点k定义了两个有效边(u -> k)(k -> v) (如果它们存在于图中),它们一起比路径(u -> v),然后假设uv之间的最短路径位于k;将边R的矩阵(u -> v)中的最短枢轴点设置为边(u -> k)的对应轴心点

  3. 现在我们在定义相同的页面上,算法可以像这样实现:

    // Initialise the routes matrix R
    for (int i = 0; i < N; i++) {
        for (int t = 0; t < N; t++) {
            R[i][t] = t;
        }
    }
    
    // Floyd-Warshall algorithm:
    for (int k = 0; k < N; k++) {
        for (int u = 0; u < N; u++) {
            for (int v = 0; v < N; v++) {
                if (D[u, v] > D[u, k] + D[k, v]) {
                    D[u, v] = D[u, k] + D[k, v];
                    R[u, v] = R[u, k];
                }
            }
        }
    }
    

    但我们如何阅读矩阵D

    让我们有一个图表:

    Graph

      

    在GraphViz中,它将描述如下:

    digraph G {
        0->2 [label = "1"];
        2->3 [label = "5"];
        3->1 [label = "2"];
        1->2 [label = "6"];
        1->0 [label = "7"];
    }
    

    我们首先创建一个大小为4 的二维数组(因为我们的图中确实有4个顶点)

    我们用零来初始化它的主对角线(其索引相等的项目,例如G[0, 0]G[1, 1]等),因为 从顶点到自身的最短路径长度为0,其他元素的数量非常大(表示它们之间没有边缘或无限长的边缘)。定义的元素,对应于图的边缘,我们填充边的长度:

    int N = 4;
    int[,] D = new int[N, N];
    
    for (int i = 0; i < N; i++) {
        for (int t = 0; t < N; t++) {
            if (i == t) {
                D[i, t] = 0;
            } else {
                D[i, t] = 9999;
            }
        }
    }
    
    D[0, 2] = 1;
    D[1, 0] = 7;
    D[1, 2] = 6;
    D[2, 3] = 5;
    D[3, 1] = 2;
    

    算法运行后,矩阵R将填充顶点索引,描述它们之间的最短路径。为了重建从顶点u到顶点v的路径,您需要遵循矩阵R的元素:

    List<Int32> Path = new List<Int32>();
    
    while (start != end)
    {
        Path.Add(start);
    
        start = R[start, end];
    }
    
    Path.Add(end);
    

    整个代码可以用几种方法包装:

    using System;
    using System.Collections.Generic;
    
    public class FloydWarshallPathFinder {
        private int N;
        private int[,] D;
        private int[,] R;
    
        public FloydWarshallPathFinder(int NumberOfVertices, int[,] EdgesLengths) {
            N = NumberOfVertices;
            D = EdgesLengths;
            R = null;
        }
    
        public int[,] FindAllPaths() {
            R = new int[N, N];
    
            for (int i = 0; i < N; i++)
            {
                for (int t = 0; t < N; t++)
                {
                    R[i, t] = t;
                }
            }
    
            for (int k = 0; k < N; k++)
            {
                for (int v = 0; v < N; v++)
                {
                    for (int u = 0; u < N; u++)
                    {
                        if (D[u, k] + D[k, v] < D[u, v])
                        {
                            D[u, v] = D[u, k] + D[k, v];
                            R[u, v] = R[u, k];
                        }
                    }
                }
            }
    
            return R;
        }
    
        public List<Int32> FindShortestPath(int start, int end) {
            if (R == null) {
                FindAllPaths();
            }
    
            List<Int32> Path = new List<Int32>();
    
            while (start != end)
            {
                Path.Add(start);
    
                start = R[start, end];
            }
    
            Path.Add(end);
    
            return Path;
        }
    }
    
    public class MainClass
    {
        public static void Main()
        {
            int N = 4;
            int[,] D = new int[N, N];
    
            for (int i = 0; i < N; i++) {
                for (int t = 0; t < N; t++) {
                    if (i == t) {
                        D[i, t] = 0;
                    } else {
                        D[i, t] = 9999;
                    }
                }
            }
    
            D[0, 2] = 1;
            D[1, 0] = 7;
            D[1, 2] = 6;
            D[2, 3] = 5;
            D[3, 1] = 2;
    
            FloydWarshallPathFinder pathFinder = new FloydWarshallPathFinder(N, D);
    
            int start = 0;
            int end = 1;
    
            Console.WriteLine("Path: {0}", String.Join(" -> ", pathFinder.FindShortestPath(start, end).ToArray()));
        }
    }
    

    您可以在wikipedia上阅读'回合此算法,并自动生成一些数据结构here

答案 1 :(得分:4)

当您使用Floyd算法时,它仅保存从图形的节点i到节点j的最短距离。因此,您还可以保存节点的路径。怎么做?

实现它的方法之一 - 是保存父节点(节点,它是路径中当前节点的先前节点)节点。您将创建另一个包含路径的矩阵。它看起来像这样:

int[,] pathS = new int[matrixDimention, matrixDimention];
for (int i = 0; i < splitValues.Length; i++){
    intValues[i / (matrixDimention), i % (matrixDimention)] = Convert.ToInt32(splitValues[i]);
    pathS[i / (matrixDimention), i % (matrixDimention)] = -1;    
}
.....
for (int k = 1; k < n+1; k++)
    for (int i = 1; i < n+1; i++)
        for (int j = 1; j < n+1; j++)
            if (intValues[i, j] > intValues[i, k] + intValues[k, j]){                
                intValues[i, j] = intValues[i, k] + intValues[k, j];
                pathS[i,j] = k;
                string str_intvalues = intValues[i, j].ToString();
                MessageBox.Show("Shortest Path from i to j is: " + str_intvalues);
            }
            else{                
                string str_intvalues = intValues[i, j].ToString();
                MessageBox.Show("Shortest Path from i to j is: " + str_intvalues);
            }

现在您有了另外的pathS数组,其中包含节点i和j之间的中间路径。为了更好地理解,你应该考虑,pathS [i,j]是这两个节点之间的节点(例如i - > [k] - > j)。但是你的路径可能比3个节点更长(这就是我在[]括号中编写节点k的原因)。所以,现在你必须检查i和k之间的路径 - 路径[i,k]和k和j之间的路径 - 路径[k,j]。并递归地执行相同操作,直到某些i和j之间的路径等于“-1”。