为什么我的TSP小算法解算器实现中很少有单独的闭环?

时间:2019-04-23 06:32:11

标签: c# algorithm winforms matrix

我正在尝试使用分支定界方法和Little的算法来实现TSP求解器。该软件本身应用于演示离散数学的演示。

利用Little的算法,我找到了一个候选游览,然后应该与其他候选游览进行比较。但是,在进入分支和界限之前,我就遇到了Little的算法实现结果带来的问题。

我使用double.positiveinfinity删除我已经检查过的路由,以及反向路由和从点x到点x的路由。

算法本身如下:

  1. 获取所有可能路线的距离矩阵
  2. 找到每一行的最小元素
  3. 对于所有行,从该行的每个元素中减去对应行的最小元素(无限个元素除外)
  4. 查找每列的最小元素
  5. 对于所有cols,应从该col中的每个元素中减去对应的col的最小元素,但无穷大元素除外

我们将在每一行和每一列中至少获得1个零。

  1. 对于矩阵中的每个零元素,计算一个值作为相应行的最小元素与相应col的最小元素之和(不包括该零元素本身)
  2. 查找具有最高计算值的零元素。这是我们将包含在行程中的路线
  3. 使用该零元素从矩阵行和列中删除。另外,从帐户中删除“后退路线元素”(例如,我们发现路线3> 4,这意味着我们将不再浏览4> 3,因此我们删除了元素(4,3))。这是通过将double.positiveinfinity分配给该行和该列的元素以及反向路由元素
  4. 来完成的
  5. 如果我们没有完整的导览,请转到第2步以获取新矩阵

下面是我编写的函数。

//find minimum element in row i of matrix m excluding element with number exc
        private double GetRowMin(double[,] m, int i, int exc = -1)
        {
            double[] SubRow = new double[m.GetLength(1)];
            Buffer.BlockCopy(m, 8 * m.GetLength(1) * i, SubRow, 0, 8 * m.GetLength(1));
            if (exc != -1)
                SubRow[exc] = Double.PositiveInfinity;
            return SubRow.Min();
        }

//find minimum element in col j of matrix m excluding element with number exc
        private double GetColMin(double[,] m, int j, int exc = -1)
        {
            double[] SubCol = new double[m.GetLength(0)];
            SubCol = Enumerable.Range(0, m.GetLength(0)).Select(xr => m[xr, j]).ToArray();
            if (exc != -1)
                SubCol[exc] = Double.PositiveInfinity;
            return SubCol.Min();
        }

//reduce matrix m by subtracting minimum for every row and col
        private double[,] MReduce(double[,] m)
        {
            double[,] resm = new double[m.GetLength(0), m.GetLength(1)];
            for (int i = 0; i < m.GetLength(0); i++)
                for (int j = 0; j < m.GetLength(1); j++)
                    if (m[i, j] < Double.PositiveInfinity)
                        resm[i, j] = m[i, j] - GetRowMin(m, i, i);
                    else
                        resm[i, j] = Double.PositiveInfinity;
            for (int i = 0; i < m.GetLength(0); i++)
                for (int j = 0; j < m.GetLength(1); j++)
                    if (m[i, j] < Double.PositiveInfinity)
                        resm[i, j] = m[i, j] - GetColMin(m, j, j);
                    else
                        resm[i, j] = Double.PositiveInfinity;
            return resm;
        }

//find zero element with maximum value
        private Point FindMaxVElem(double[,] m)
        {
            double MaxV = Double.MinValue;
            Point MaxP = new Point();
            for (int i = 0; i < m.GetLength(0); i++)
                for (int j = 0; j < m.GetLength(1); j++)
                    if (m[i, j] == 0)
                    {
                        double s = 0;
                        if (!Double.IsInfinity(GetRowMin(m, i, j)))
                            s += GetRowMin(m, i, j);
                        if (!Double.IsInfinity(GetColMin(m, j, i)))
                            s += GetColMin(m, j, i);
                        if (Double.IsInfinity(s))
                            s = 0;
                        if (s > MaxV)
                        {
                            MaxV = s;
                            MaxP.X = i;
                            MaxP.Y = j;
                        }
                    }
            return MaxP;
        }

//delete row/col and backroute from accounting
        private double[,] RCSubtract(double[,] m, int l, int n)
        {
            double[,] resm = new double[m.GetLength(0), m.GetLength(1)];
            for (int i = 0; i < m.GetLength(0); i++)
                for (int j = 0; j < m.GetLength(1); j++)
                {
                    if (i == l || j == n)
                        resm[i, j] = Double.PositiveInfinity;
                    else
                        resm[i, j] = m[i, j];
                }
            resm[n, l] = Double.PositiveInfinity;
            return resm;
        }

驱动程序代码如下:

public List<PointD> PList; //list for storing coordinates of all points
        double[,] AdjM; //distance matrix
        List<Point> path; //here will be unordered subroutes of the tour

...

for (int i = 0; i < PList.Count; i++)
            {
                AdjM = MReduce(AdjM);
                path.Add(FindMaxVElem(AdjM));
                AdjM = RCSubtract(AdjM, path.Last().X, path.Last().Y);
            }

在大多数情况下(简单和复杂),一切都很好,并且可以找到游览。问题是,我的Little的算法算法不是在几个紧密定位的点的单独组上,而不是对所有点进行完全封闭的巡回显示,而是返回几个单独的封闭的游览,如下所示:

(猜测我没有足够的声誉来发布图片,对不起)https://pp.userapi.com/c849236/v849236895/174a46/ASAPt1F8zs4.jpg

逐步矩阵正像这样求解:

    0     1     2     3     4     5     Min
--------------------------------------------
 0: нет   25,4  31,5  146,3 159,6 140,2 25,4 
 1: 25,4  нет   24,8  160,3 176,3 159,3 24,8 
 2: 31,5  24,8  нет   138,3 155,9 141,2 24,8 
 3: 146,3 160,3 138,3 нет   26,3  40,8  26,3 
 4: 159,6 176,3 155,9 26,3  нет   27,9  26,3 
 5: 140,2 159,3 141,2 40,8  27,9  нет   27,9 
Min 25,4  24,8  24,8  26,3  26,3  27,9  310,9

    0     1     2     3     4     5     Min
--------------------------------------------
 0: нет   0,5   6,7   120,1 нет   112,4 0,5  
 1: 0     нет   0     134,1 нет   131,5 0    
 2: 6,2   0     нет   112   нет   113,3 0    
 3: нет   нет   нет   нет   нет   нет   нет  
 4: 134,2 151,5 131   нет   нет   0     0    
 5: 114,9 134,5 116,3 14,6  нет   нет   14,6 
Min 0     0     0     14,6  нет   0     29,7 

    0     1     2     3     4     5     Min
--------------------------------------------
 0: нет   0,5   6,7   105,5 нет   нет   0,5  
 1: 0     нет   0     119,5 нет   нет   0    
 2: 6,2   0     нет   97,4  нет   нет   0    
 3: нет   нет   нет   нет   нет   нет   нет  
 4: нет   нет   нет   нет   нет   нет   нет  
 5: 114,9 134,5 116,3 0     нет   нет   0    
Min 0     0     0     0     нет   нет   0,5  

    0     1     2     3     4     5     Min
--------------------------------------------
 0: нет   0,5   6,7   нет   нет   нет   0,5  
 1: 0     нет   0     нет   нет   нет   0    
 2: 6,2   0     нет   нет   нет   нет   0    
 3: нет   нет   нет   нет   нет   нет   нет  
 4: нет   нет   нет   нет   нет   нет   нет  
 5: нет   нет   нет   нет   нет   нет   нет  
Min 0     0     0     нет   нет   нет   0,5  

    0     1     2     3     4     5     Min
--------------------------------------------
 0: нет   0,5   нет   нет   нет   нет   0,5  
 1: нет   нет   нет   нет   нет   нет   нет  
 2: 6,2   нет   нет   нет   нет   нет   6,2  
 3: нет   нет   нет   нет   нет   нет   нет  
 4: нет   нет   нет   нет   нет   нет   нет  
 5: нет   нет   нет   нет   нет   нет   нет  
Min 6,2   0,5   нет   нет   нет   нет   13,4 

    0     1     2     3     4     5     Min
--------------------------------------------
 0: нет   нет   нет   нет   нет   нет   нет  
 1: нет   нет   нет   нет   нет   нет   нет  
 2: 0     нет   нет   нет   нет   нет   0    
 3: нет   нет   нет   нет   нет   нет   нет  
 4: нет   нет   нет   нет   нет   нет   нет  
 5: нет   нет   нет   нет   нет   нет   нет  
Min 0     нет   нет   нет   нет   нет   0        

所以我知道我做错了(可能搞砸了无穷大),因为已经在单独定位的点组上进行第一次迭代返回了一些封闭的巡回路线,而不是一次。但我无法弄清楚到底出了什么问题。有人有什么想法吗?

0 个答案:

没有答案