【问题标题】:Convert Distance between points to Point将点之间的距离转换为点
【发布时间】:2023-12-13 15:20:01
【问题描述】:

给定起点和距离,计算终点。 我有一个与客户的矩阵,它们之间的距离。 (见链接jsfiddle)

矩阵:http://jsfiddle.net/j69kA/

如何将它的校正转换为基于中心点的坐标点 (X, Y)?可以是 1。

    1   2   3   4   5   6   7   8   9   10
1   0   24  15  27  19  16  11  33  28  30
2   24  0   28  32  29  17  20  20  27  30
3   15  28  0   19  22  12  22  29  29  15
4   27  32  19  0   29  23  13  31  20  28
5   19  29  22  29  0   24  25  17  22  23
6   16  17  12  23  24  0   22  23  21  12
7   11  20  22  13  25  22  0   28  23  19
8   33  20  29  31  17  23  28  0   28  22
9   28  27  29  20  22  21  23  28  0   25
10  30  30  15  28  23  12  19  22  25  0

【问题讨论】:

    标签: c# matrix distance coordinate


    【解决方案1】:

    不幸的是,您正在尝试做的是不可能

    为什么?

    因为有不止一组点会产生上面的距离矩阵。

    为了证明这一点,假设您有一张点地图,其距离对应于该矩阵。

    现在在 Y 轴上反映这张地图。相对距离不变 => 不同的点图,相同的矩阵!

    现在在 X 轴上反映这张地图。相对距离不变 => 不同的点图,相同的矩阵!

    现在将其旋转 90 度。同样,距离不变 => 再次使用相同的矩阵!

    你看到这里的模式了吗?

    事实上,有无限个可能的 X、Y 点集可以生成您在上面显示的距离矩阵。

    简而言之,没有一对一的映射。这是多对一的。当您从一组点转到距离矩阵时,您会丢弃有价值的信息,之后您将无法将其取回。

    如果你只是想得到点之间的最短路径(而不关心坐标系),那么Dijkstra算法就是你所需要的。

    在您的情况下,您在每个点之间都有直接距离,但可能想看看间接路径是否会更短。在这种情况下,以下控制台应用程序(刚刚编写并且除了您的数据之外大部分未经测试)应该可以满足您的需求:

    namespace DijkstraTest
    {
        class Node
        {
            public Node(int index)
            {
                distanceFromStart = -1;
                this.index = index;
            }
    
            public int distanceFromStart;
            public bool visited;
            public Node parent;
            public int index;
        }
    
        class Dijkstra
        {
            private int[,] distanceMatrix;
            private int size;
    
            public Dijkstra(int[,] distanceMatrix)
            {
                this.distanceMatrix = distanceMatrix;
                size = distanceMatrix.GetLength(0);
                if (distanceMatrix.Rank != 2 || (size != distanceMatrix.GetLength(1)))
                    throw new ArgumentException("Matrix must be 2-D and square!");
            }
    
            public List<Node> GetShortestPath(int startPos, int endPos)
            {
                var nodes = Enumerable.Range(0, size).Select(i => new Node(i)).ToList();
                nodes[startPos].distanceFromStart = 0;
                var endNode = nodes[endPos];
    
                while (!endNode.visited)
                {
                    var currentNode = nodes.Where(i => !i.visited && i.distanceFromStart != -1)
                                           .OrderBy(i => i.distanceFromStart).First();
    
                    foreach (var neighbour in nodes
                                 .Where(i => !i.visited && distanceMatrix[currentNode.index, i.index] != -1))
    
                    {
                        var thisDistance = currentNode.distanceFromStart +
                                           distanceMatrix[currentNode.index, neighbour.index];
    
                        if (neighbour.distanceFromStart == -1 || neighbour.distanceFromStart > thisDistance)
                        {
                            neighbour.distanceFromStart = thisDistance;
                            neighbour.parent = currentNode;
                        }
                    }
                    currentNode.visited = true;
                }
    
                // build the results working back
                var retVal = new List<Node> {endNode};
    
                while (endNode.parent != null)
                {
                    endNode = endNode.parent;
                    retVal.Add(endNode);
                } 
    
                retVal.Reverse();
                return retVal;
            }
        }
    
        class Program
        {
            static int[,] DistanceMatrix = {{-1,   24,  15,  27,  19,  16,  11,  33,  28,  30},
                                            {24,  -1,   28,  32,  29,  17,  20,  20,  27,  30},
                                            {15,  28,  -1,   19,  22,  12,  22,  29,  29,  15},
                                            {27,  32,  19,  -1,   29,  23,  13,  31,  20,  28},
                                            {19,  29,  22,  29,  -1,   24,  25,  17,  22,  23},
                                            {16,  17,  12,  23,  24,  -1,   22,  23,  21,  12},
                                            {11,  20,  22,  13,  25,  22,  -1,   28,  23,  19},
                                            {33,  20,  29,  31,  17,  23,  28,  -1,   28,  22},
                                            {28,  27,  29,  20,  22,  21,  23,  28,  -1,   25},
                                            {30,  30,  15,  28,  23,  12,  19,  22,  25,  -1}};
    
            static void Main(string[] args)
            {
                var dijkstra = new Dijkstra(DistanceMatrix);
    
                for (int i = 0; i < 10; i++)
                {
                    for (int j = i; j < 10; j++)
                    {
                        var path = dijkstra.GetShortestPath(i, j);
                        // print complex paths that are shorter than just going straight there...
                        if (path.Count > 2)
                        {
                            Console.Write("From {0} to {1}: ", i,j);
                            foreach (var item in path)
                            {
                                Console.Write(" {0} ", item.index);
                            }
                            Console.WriteLine(": Total distance: {0}, Direct distance: {1}", 
                                path.Last().distanceFromStart, DistanceMatrix[i,j]);
                        }
                    }
                }
            }
        }
    

    这是相当粗略的准备,但它似乎产生了合理的输出。使用您的距离矩阵,您将获得以下输出(比直接更短的间接路径):

    From 0 to 3:  0  6  3 : Total distance: 24, Direct distance: 27
    From 0 to 9:  0  5  9 : Total distance: 28, Direct distance: 30
    From 1 to 9:  1  5  9 : Total distance: 29, Direct distance: 30
    

    它基于*文章here,直接翻译成C#。

    【讨论】:

      【解决方案2】:

      要构建一个笛卡尔系统,您需要两个点 -> 起点、终点

      你的矩阵只包含两点之间的距离,而不是起点和终点。

      您需要将其转换为笛卡尔系统(使用 XY 平面)。

      你说原点是1。

      你会如何建议这个系统,因为它不能是笛卡尔的,因为在这种情况下你希望 Destination 指向。

      我建议使用极坐标系,两点之间的角度相等。

      编辑: 来自http://www.c-program-example.com/

      使用:

      #include "stdio.h"
      #define infinity 999
      
      void dij(int n,int v,int cost[10][10],int dist[])
      {
        int i,u,count,w,flag[10],min;
        for(i=1;i<=n;i++)
              flag[i]=0,dist[i]=cost[v][i];
        count=2;
        while(count<=n)
        {
              min=99;
              for(w=1;w<=n;w++)
                    if(dist[w]<min && !flag[w])
                          min=dist[w],u=w;
              flag[u]=1;
              count++;
              for(w=1;w<=n;w++)
                    if((dist[u]+cost[u][w]<dist[w]) && !flag[w])
                          dist[w]=dist[u]+cost[u][w];
        }
      }
      
      void start()
      {
        int n,v,i,j,cost[10][10],dist[10];
        printf("\n Enter the number of nodes:");
        scanf("%d",&n);
        printf("\n Enter the cost matrix:\n");
        for(i=1;i<=n;i++)
              for(j=1;j<=n;j++)
              {
                    scanf("%d",&cost[i][j]);
                          if(cost[i][j]==0)
                    cost[i][j]=infinity;
              }
        printf("\n Enter the source matrix:");
        scanf("%d",&v);
        dij(n,v,cost,dist);
        printf("\n Shortest path:\n");
        for(i=1;i<=n;i++)
              if(i!=v)
                    printf("%d->%d,cost=%d\n",v,i,dist[i]);
      }
      

      【讨论】:

      • 我不是在寻找完美的答案,我必须用它来尝试解决“VRP”(车辆路线问题)。即便如此,也不可能吗?
      • 顺便说一句,如果你说你的原点是 1,这也意味着两点之间的最短距离将是一包括两个相同点之间的距离。
      • @Zen 我可以建议,您可以使用与您的原点距离给定的随机目的地(您说 1)。因此,您可以获得(X-Y)平面。虽然你的 X-Y 平面上的目标点坐标应该没有意义
      • 顺便说一句,当我说 Origin 是 1. 1 = (0,0)。我有“虚构”点的距离矩阵。我需要计算我能找到的最佳路线(不完美!这个问题没有完美的路线。)。但是我发现的所有算法,我都需要给出坐标。 X/Y。这就是为什么我想将其转换为 Coord。 X/Y。
      • @Zen,您可以使用最短路径算法,而不是将这些转换为 x/y。有很多可用的资源。在许多情况下,您当前的矩阵表示格式也是理想的。我认为您的矩阵可以在Dijkstra's Algorithm 上完美运行。可以看一个C编程例子here还有see