C 使用Floyd Warshall算法确定;“奇数”;矩阵

C 使用Floyd Warshall算法确定;“奇数”;矩阵,c,algorithm,path-finding,floyd-warshall,C,Algorithm,Path Finding,Floyd Warshall,基本上,使用Floyd-Warshall算法的目的是确定连通图中两个节点之间的最短路径。我试图做的不是简单地寻找最短的路径,我希望最短的路径也是一个均匀的权重 例如,这是Floyd Warshall算法的一个简单实现: #include <stdio.h> main() { int dist[10][10],succ[10][10],n,i,j,k; int newDist; scanf("%d",&n); for (i=0;i<n;i

基本上,使用Floyd-Warshall算法的目的是确定连通图中两个节点之间的最短路径。我试图做的不是简单地寻找最短的路径,我希望最短的路径也是一个均匀的权重

例如,这是Floyd Warshall算法的一个简单实现:

#include <stdio.h>

main()
{
   int dist[10][10],succ[10][10],n,i,j,k;
    int newDist;

    scanf("%d",&n);
    for (i=0;i<n;i++)
        for (j=0;j<n;j++)
        {
            dist[i][j]=999;
            succ[i][j]=j;
        }

    while (1)
    {
        scanf("%d %d %d",&i,&j,&k);

        if (i==(-1))
            break;

        dist[i][j]=k;
        distOdd[i][j]=k;
        distEven[i][j]=k;
    }

    printf("    ");

    for (i=0;i<n;i++)
        printf("%3d   ",i);

    printf("\n");

    for (i=0;i<n;i++)
    {
        printf("%3d ",i);

        for (k=0;k<n;k++)
            printf("%3d %d ",dist[i][k],succ[i][k]);

        printf("\n");
    }

    printf("-------------------------------\n");

    /* Floyd-Warshall */
    for (j=0;j<n;j++)
    {
        for (i=0;i<n;i++)
            if (dist[i][j]<999)
                for (k=0;k<n;k++)
                {
                    newDist=dist[i][j]+dist[j][k];
                    if (newDist<dist[i][k])
                    {
                        dist[i][k]=newDist;
                        succ[i][k]=succ[i][j];
                    }
                }

        printf("    ");

        for (i=0;i<n;i++)
            printf("%3d   ",i);
        printf("\n");

        for (i=0;i<n;i++)
        {
            printf("%3d ",i);

            for (k=0;k<n;k++)
                printf("%3d %d ",dist[i][k],succ[i][k]);

            printf("\n");
        }

        printf("-------------------------------\n");
    }

    for (i=0;i<n;i++)
        for (j=0;j<n;j++)
            if (dist[i][j]==999)
                printf("No path from %d to %d\n",i,j);
            else
            {
                printf("Distance %d for %d ",dist[i][j],i);
                for (k=succ[i][j];
                    k!=j;
                    k=succ[k][j])
                        printf("%d ",k);

                printf("%d\n",j);
            }
}
我想要以下输出(忽略格式,我只需要一种方法来找到“每一步的奇数矩阵”)

我的代码目前所做的是,它获得了在每个单独的“奇数”和“偶数”矩阵中表示的最佳权重


我缺乏理解的是,当最优值位于相反的矩阵(奇数/偶数)中时,“奇数”和“偶数”矩阵如何得出它们的非最优值。在我看来,必须有某种循环或递归才能做到这一点,但我不知道如何做到这一点。

在C中不是,但这不应该是一个问题。我认为F-W需要两种修改才能获得最短奇偶路径:

  • 它需要运行两次。这是因为如果路径本身循环,它可能会切换均匀度。如图中所示:a--5-->B--2-->(返回到a)。要在均匀路径上从a到B,我们需要运行a-B-a-B。但是,如果我们无法使某个均匀度的路径运行两次,则没有必要运行两次以上

  • 为了找到更好的路径,您需要尝试所有的组合(请参阅从0到1的最内层循环)。到目前为止,偶数路径可能会通过添加奇数边等方式成为新的最佳奇数路径

  • 我认为这个算法应该是正确的,如果你发现任何错误,请随意对我大喊大叫

    编辑:添加路径记忆(标记为//added的部分)。当然,这会使算法内存效率低下,因此只有在确实需要时才应使用。在这种情况下,我想不出一种方法来让标准F-W路径重建工作。由于路径可能比顶点数长,我不确定路径重建将如何工作。我没有测试路径记忆所以它可能被窃听了。不过可能工作正常

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication5
    {
        class Program
        {
            static void Main(string[] args)
            {
                int n = 5;
    
                // Generate graph
                Random r = new Random(1);
                // ADDED
                List<int>[,,] path = new List<int>[n, n, 2];
                int[,,] cost = new int[n, n, 2];
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        // ADDED
                        path[i, j, 0] = new List<int>{i};
                        path[i, j, 1] = new List<int>{i};
    
                        if (i == j)
                        {
                            cost[i, j, 0] = 0;
                            cost[i, j, 1] = -1;
                            continue;
                        }
                        int x = r.Next() % 9 + 1;
    
                        if (r.Next(100) < 60)
                        {
                            cost[i, j, 0] = -1;
                            cost[i, j, 1] = -1;
                            continue;
                        }
    
                        cost[i, j, x % 2] = x;
                        cost[i, j, 1 - (x % 2)] = -1;
                    }
                }
    
                // Print edge weights
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        if (cost[i, j, 0] != -1)
                            Console.Write(cost[i, j, 0] + "\t");
                        else
                            Console.Write(cost[i, j, 1] + "\t");
                    }
                    Console.WriteLine(" ");
                }
                Console.ReadLine();
    
                // Find shortest odd and even paths
                for (int s = 0; s < 2; s++)
                {
                    for (int k = 0; k < n; k++)
                        for (int i = 0; i < n; i++)
                            for (int j = 0; j < n; j++)
                                for (int u = 0; u <= 1; u++)
                                    for (int v = 0; v <= 1; v++)
                                    {
                                        if (cost[i, k, u] == -1 || cost[k, j, v] == -1)
                                            continue;
                                        int newCost = cost[i, k, u] + cost[k, j, v];
                                        if (newCost < cost[i, j, newCost % 2] || cost[i, j, newCost % 2] == -1)
                                        {
                                            cost[i, j, newCost % 2] = newCost;
                                            // ADDED
                                            path[i, j, newCost % 2] = path[i, k, u].Concat(path[k, j, v]).ToList();
                                        }
                                    }
                }
    
                // Print results
                Console.WriteLine("\nShortest even paths: ");
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                        Console.Write(cost[i, j, 0] + "\t");
                    Console.WriteLine(" ");
                }
    
                Console.WriteLine("\nShortest odd paths:");
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                        Console.Write(cost[i, j, 1] + "\t");
                    Console.WriteLine(" ");
                }
    
                Console.WriteLine();
    
                // ADDED
                // Example, print shortest odd path between vertices 3 and 1
                // This does not print the final q vertex
                int p = 3;
                int q = 1;
                foreach (int index in path[p, q, 1])
                    Console.Write(index);
    
                Console.ReadLine();
            }
        }
    }
    
    使用系统;
    使用System.Collections.Generic;
    使用System.Linq;
    使用系统文本;
    命名空间控制台应用程序5
    {
    班级计划
    {
    静态void Main(字符串[]参数)
    {
    int n=5;
    //生成图形
    随机r=新随机(1);
    //增加
    列表[,]路径=新列表[n,n,2];
    整数[,]成本=新整数[n,n,2];
    对于(int i=0;i对于(int u=0;u,我不确定这是否有效,但值得一试:将权重拆分为
    distOdd
    dist偶数
    矩阵,然后运行三个嵌套循环。在每个步骤上执行四个任务:(1)检查
    [I][j]
    [j][k]
    处的两个偶数路径是否可以改善
    [I][k]
    处的偶数路径,(2)查看两条奇数路径是否可以改善
    [i][k]
    处的偶数路径,以及(3)查看
    [i][j]
    处的奇数路径和
    [j][k]
    处的偶数路径是否可以改善
    [i][k]
    处的奇数路径,以及(4)查看
    [i][j]
    处的偶数路径和
    [j][k]
    处的奇数路径是否可以改善
    [i][k]处的奇数路径
    @dasblinkenlight我的问题是算法已经找到了最优化的路径。例如,在
    处理第3列期间,
    2->1
    中的最佳路径的权重为“2”,但由于2是一个偶数,它不知怎的找到了数字“5”,该数字似乎是通过节点3循环一次得到的,并且由于算法m不支持递归性,我要么需要以某种方式添加它,要么找到另一种方法来找到它。我有点困惑三维
    是如何花费[,]
    正在运行。难道不需要两个不同的矩阵来获得奇数和偶数路径吗?它们实际上只是两个二维矩阵,因为第三维是2。cost[x,y,0]是偶数矩阵,cost[x,y,1]是奇数矩阵。我用它来代替两个变量,这样我就可以编写cost[I,j,newCost%2]之类的东西=newCost而不是“if偶数更新偶数矩阵,else更新奇数矩阵”此方法是否允许您使用后续方法来追溯您所走的路径?据我所知(我还无法测试),它应该能够准确地找到我所要求的,但如果我想
    initial odd matrix
    999 0   1 1 999 2 999 3 999 4 999 5 
    999 0 999 1   1 2 999 3   1 4 999 5 
    999 0 999 1 999 2   1 3 999 4 999 5 
    999 0   1 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4   1 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    -------------------------------
    Process column 0
    odd matrix
    999 0   1 1 999 2 999 3 999 4 999 5 
    999 0 999 1   1 2 999 3   1 4 999 5 
    999 0 999 1 999 2   1 3 999 4 999 5 
    999 0   1 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4   1 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    even matrix
    999 0 999 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    -------------------------------
    Process column 1
    odd matrix
    999 0   1 1 999 2 999 3 999 4 999 5 
    999 0 999 1   1 2 999 3   1 4 999 5 
    999 0 999 1 999 2   1 3 999 4 999 5 
    999 0   1 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4   1 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    even matrix
    999 0 999 1   2 1 999 3   2 1 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    999 0 999 1   2 1 999 3   2 1 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    -------------------------------
    Process column 2
    odd matrix
    999 0   1 1 999 2   3 1 999 4 999 5 
    999 0 999 1   1 2 999 3   1 4 999 5 
    999 0 999 1 999 2   1 3 999 4 999 5 
    999 0   1 1 999 2   3 1 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4   1 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    even matrix
    999 0 999 1   2 1 999 3   2 1 999 5 
    999 0 999 1 999 2   2 2 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    999 0 999 1   2 1 999 3   2 1 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    -------------------------------
    Process column 3
    odd matrix
    999 0   1 1   5 1   3 1   5 1 999 5 
    999 0   3 2   1 2   5 2   1 4 999 5 
    999 0   5 3   3 3   1 3   3 3 999 5 
    999 0   1 1   5 1   3 1   5 1 999 5 
    999 0 999 1 999 2 999 3 999 4   1 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    even matrix
    999 0   4 1   2 1   6 1   2 1 999 5 
    999 0   6 2   4 2   2 2   4 2 999 5 
    999 0   2 3   6 3   4 3   6 3 999 5 
    999 0   4 1   2 1   6 1   2 1 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    -------------------------------
    Process column 4
    odd matrix
    999 0   1 1   5 1   3 1   5 1   3 1 
    999 0   3 2   1 2   5 2   1 4   5 2 
    999 0   5 3   3 3   1 3   3 3   7 3 
    999 0   1 1   5 1   3 1   5 1   3 1 
    999 0 999 1 999 2 999 3 999 4   1 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    even matrix
    999 0   4 1   2 1   6 1   2 1   6 1 
    999 0   6 2   4 2   2 2   4 2   2 4 
    999 0   2 3   6 3   4 3   6 3   4 3 
    999 0   4 1   2 1   6 1   2 1   6 1 
    999 0 999 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    -------------------------------
    Process column 5
    odd matrix
    999 0   1 1   5 1   3 1   5 1   3 1 
    999 0   3 2   1 2   5 2   1 4   5 2 
    999 0   5 3   3 3   1 3   3 3   7 3 
    999 0   1 1   5 1   3 1   5 1   3 1 
    999 0 999 1 999 2 999 3 999 4   1 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    even matrix
    999 0   4 1   2 1   6 1   2 1   6 1 
    999 0   6 2   4 2   2 2   4 2   2 4 
    999 0   2 3   6 3   4 3   6 3   4 3 
    999 0   4 1   2 1   6 1   2 1   6 1 
    999 0 999 1 999 2 999 3 999 4 999 5 
    999 0 999 1 999 2 999 3 999 4 999 5 
    -------------------------------
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication5
    {
        class Program
        {
            static void Main(string[] args)
            {
                int n = 5;
    
                // Generate graph
                Random r = new Random(1);
                // ADDED
                List<int>[,,] path = new List<int>[n, n, 2];
                int[,,] cost = new int[n, n, 2];
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        // ADDED
                        path[i, j, 0] = new List<int>{i};
                        path[i, j, 1] = new List<int>{i};
    
                        if (i == j)
                        {
                            cost[i, j, 0] = 0;
                            cost[i, j, 1] = -1;
                            continue;
                        }
                        int x = r.Next() % 9 + 1;
    
                        if (r.Next(100) < 60)
                        {
                            cost[i, j, 0] = -1;
                            cost[i, j, 1] = -1;
                            continue;
                        }
    
                        cost[i, j, x % 2] = x;
                        cost[i, j, 1 - (x % 2)] = -1;
                    }
                }
    
                // Print edge weights
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        if (cost[i, j, 0] != -1)
                            Console.Write(cost[i, j, 0] + "\t");
                        else
                            Console.Write(cost[i, j, 1] + "\t");
                    }
                    Console.WriteLine(" ");
                }
                Console.ReadLine();
    
                // Find shortest odd and even paths
                for (int s = 0; s < 2; s++)
                {
                    for (int k = 0; k < n; k++)
                        for (int i = 0; i < n; i++)
                            for (int j = 0; j < n; j++)
                                for (int u = 0; u <= 1; u++)
                                    for (int v = 0; v <= 1; v++)
                                    {
                                        if (cost[i, k, u] == -1 || cost[k, j, v] == -1)
                                            continue;
                                        int newCost = cost[i, k, u] + cost[k, j, v];
                                        if (newCost < cost[i, j, newCost % 2] || cost[i, j, newCost % 2] == -1)
                                        {
                                            cost[i, j, newCost % 2] = newCost;
                                            // ADDED
                                            path[i, j, newCost % 2] = path[i, k, u].Concat(path[k, j, v]).ToList();
                                        }
                                    }
                }
    
                // Print results
                Console.WriteLine("\nShortest even paths: ");
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                        Console.Write(cost[i, j, 0] + "\t");
                    Console.WriteLine(" ");
                }
    
                Console.WriteLine("\nShortest odd paths:");
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                        Console.Write(cost[i, j, 1] + "\t");
                    Console.WriteLine(" ");
                }
    
                Console.WriteLine();
    
                // ADDED
                // Example, print shortest odd path between vertices 3 and 1
                // This does not print the final q vertex
                int p = 3;
                int q = 1;
                foreach (int index in path[p, q, 1])
                    Console.Write(index);
    
                Console.ReadLine();
            }
        }
    }