2015-11-11 55 views
4

我一直試圖在Java中實現Floyd-Warshall算法,但沒有使用「三for-loop-nested」方法,但我似乎無法弄清楚我在代碼中出錯的地方。Simple Floyd-Warshall算法Java實現似乎不工作?

這是顯示我的頂點如何連接的地圖。白色數字是頂點,黑色數字是連接頂點之間的距離。

地圖頂點:http://i.imgur.com/htcaA4y.png

正在運行的迭代之後,我得到下面的最終距離和序列矩陣。說「有問題」的東西是最後一個序列矩陣(右邊一列)的第8列。爲了從任何其他頂點到達頂點8,路徑必須首先從頂點8到9,然後從THEN到10(根據矩陣它不是這種情況 - 它從頂點8直到10)。

輸出矩陣:http://i.imgur.com/o6fQweH.png

下面的代碼。什麼似乎是這個問題?


import java.util.ArrayList; 

public class Main_Simple { 

    public static void main(String[] args) { 

     // 1. Setup the distance matrix 
     // -inf for vertices that are not connected 
     // -### for edge weights of vertices that are connected 
     // -0 across the diagonal 

     int inf = 1000000; // Temporary 'infinity' variable 

     // Initial distance matrix must be n x n 
     int[][] initialDistanceMatrix = { 
       {0, 1, inf, 1, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf}, 
       {1, 0, 1, inf, 1, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf}, 
       {inf, 1, 0, inf, inf, 1, inf, inf, inf, inf, inf, inf, inf, inf, inf}, 
       {1, inf, inf, 0, 1, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf}, 
       {inf, 1, inf, 1, 0, 1, inf, inf, inf, inf, inf, inf, inf, inf, inf}, 
       {inf, inf, 1, inf, 1, 0, 2, inf, inf, 1, inf, inf, inf, inf, inf}, 
       {inf, inf, inf, inf, inf, 2, 0, inf, inf, inf, inf, inf, inf, inf, inf}, 
       {inf, inf, inf, inf, inf, inf, inf, 0, 1, inf, inf, inf, inf, inf, inf}, 
       {inf, inf, inf, inf, inf, inf, inf, 1, 0, 1, inf, inf, inf, inf, inf}, 
       {inf, inf, inf, inf, inf, 1, inf, inf, 1, 0, 2, 1, inf, inf, inf}, 
       {inf, inf, inf, inf, inf, inf, inf, inf, inf, 2, 0, inf, inf, inf, 2}, 
       {inf, inf, inf, inf, inf, inf, inf, inf, inf, 1, inf, 0, 1, inf, inf}, 
       {inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, 1, 0, 1, inf}, 
       {inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, 1, 0, 1}, 
       {inf, inf, inf, inf, inf, inf, inf, inf, inf, inf, 2, inf, inf, 1, 0} 
     }; 

     // 2. Setup the sequence matrix 
     // -All of column-1 are ones 
     // -All of column-2 are twos 
     // -etc 
     // -0 across the diagonal 

     // Initial sequence matrix must be the same size as the initial distance matrix 
     int[][] initialSequenceMatrix = new int[initialDistanceMatrix.length][initialDistanceMatrix.length]; 
     for (int row = 0; row < initialSequenceMatrix.length; row++) { 
      for (int column = 0; column < initialSequenceMatrix.length; column++) { 
       if (row == column) { 
        initialSequenceMatrix[row][column] = 0; 
       } else { 
        initialSequenceMatrix[row][column] = column + 1; // +1 to account 0-based array 
       } 
      } 
     } 

     // 3. Iterate through the matrices (n-1) times 
     // -On the kth iteration, copy the kth column and kth row down to the next distance and sequence matrix 
     // -On the kth iteration, check matrix (k-1) and take the minimum of the following two: 
     //  -d(ij) 
     //  -d(ik)+d(kj) 
     //  where i = row number, j = column number, and k = iteration number 
     // -After the distance matrix has been calculated, compare the current distance matrix to the previous. 
     // If the numbers are the same, keep the sequence matrix the same. Otherwise, change the sequence 
     // matrix to the current iteration's number. 

     ArrayList<int[][]> distanceMatrices = new ArrayList<int[][]>(); 
     distanceMatrices.add(initialDistanceMatrix); 

     ArrayList<int[][]> sequenceMatrices = new ArrayList<int[][]>(); 
     sequenceMatrices.add(initialSequenceMatrix); 

     // Print the matrices to make sure they are made correctly 
     printMatrix(initialDistanceMatrix, "Initial distance matrix"); 
     printMatrix(initialSequenceMatrix, "Initial sequence matrix"); 

     // Matrix Iteration Loops 
     for (int iteration = 1; iteration < initialDistanceMatrix.length; iteration++) { 

      // Initialize new distance matrix 
      int[][] currentDistanceMatrix = new int[initialDistanceMatrix.length][initialDistanceMatrix.length]; 
      for (int row = 0; row < currentDistanceMatrix.length; row++) { 
       for (int column = 0; column < currentDistanceMatrix.length; column++) { 
        currentDistanceMatrix[row][column] = 0; 
       } // ends 'column' loop 
      } // ends 'row' loop 

      // Distance Matrix iteration 
      for (int row = 0; row < currentDistanceMatrix.length; row++) { 
       for (int column = 0; column < currentDistanceMatrix.length; column++) { 

        if (row == column) { // If you are on the diagonal, insert '0' 
         currentDistanceMatrix[row][column] = 0; 
        } else if (row == (iteration - 1) || column == (iteration - 1)) { // Brings down the row and column of the iteration (-1 to account 0-based array) 
         currentDistanceMatrix[row][column] = distanceMatrices.get(iteration - 1)[row][column]; 
        } else { // If you are on any other square... 
         int Dij = distanceMatrices.get(iteration - 1)[row][column]; 
         int Dik_Dkj = distanceMatrices.get(iteration - 1)[row][iteration - 1] + distanceMatrices.get(iteration - 1)[iteration - 1][column]; 

         if (Dij > Dik_Dkj) currentDistanceMatrix[row][column] = Dik_Dkj; 
         else currentDistanceMatrix[row][column] = Dij; 
        } 

       } // ends 'column' loop 
      } // ends 'row' loop 

      // Add the distance matrix to the matrix array 
      distanceMatrices.add(currentDistanceMatrix); 

      // Initialize new sequence matrix 
      int[][] currentSequenceMatrix = new int[initialDistanceMatrix.length][initialDistanceMatrix.length]; 

      // Sequence Matrix iteration 
      for (int row = 0; row < currentSequenceMatrix.length; row++) { 
       for (int column = 0; column < currentSequenceMatrix.length; column++) { 

        if (row == column) { // If you are along the diagonal... 
         currentSequenceMatrix[row][column] = 0; 
        } else if (row == (iteration - 1) || column == (iteration - 1)) { // If you are on the same row or column as the iteration... 
         currentSequenceMatrix[row][column] = sequenceMatrices.get(iteration - 1)[row][column]; 
        } else { // If you are on any other square... 
         // You need to check the current distance matrix to see if it matches the previous. 
         // If it does match, keep the same number. 
         // If it changed, changed the number in that cell to the current iteration 

         // Compare the most recent distance matrix to the one before it 
         if (distanceMatrices.get(distanceMatrices.size() - 1)[row][column] == distanceMatrices.get(distanceMatrices.size() - 2)[row][column]) { 
          currentSequenceMatrix[row][column] = sequenceMatrices.get(sequenceMatrices.size() - 1)[row][column]; 
         } else { 
          currentSequenceMatrix[row][column] = iteration; 
         } 
        } 

       } // ends 'column' loop 
      } // ends 'row' loop 

      // Add the sequence matrix to the matrix array 
      sequenceMatrices.add(currentSequenceMatrix); 

     } // ends matrix iteration loops 

     System.out.println("-------------------------------------------------------"); 

     printMatrix(distanceMatrices.get(distanceMatrices.size() - 1), "Final Distance Matrix"); 
     printMatrix(sequenceMatrices.get(sequenceMatrices.size() - 1), "Final Sequence Matrix"); 

    } // ends main method 

    public static void printMatrix(int[][] matrix, String message) { 
     System.out.println("\n" + message); 
     for (int row = 0; row < matrix.length; row++) { 
      for (int column = 0; column < matrix.length; column++) { 
       System.out.print(matrix[row][column] + "\t"); 
      } // ends 'column' loop 
      System.out.println(); 
     } // ends 'row' loop 
     System.out.println(); 
    } 

} // ends class Main_Simple 
+2

您是否試圖用更小的地圖來調試您的實現? –

+0

@Rhymoid是的,它似乎在5x5,6x6和7x7矩陣上工作。奇怪的是它在這張地圖上根本不起作用。也許我錯過了關於Floyd-W算法的基礎知識? – ngserdna

回答

0

你不是通過所有頂點的適當第一迭代循環。

for (int iteration = 1; iteration < initialDistanceMatrix.length; iteration++) 

應該是:

for (int iteration = 1; iteration < initialDistanceMatrix.length + 1; iteration++) 

或者,更好的,而不是使用iteration - 1爲您所有的數組索引,使用iteration,然後你可以使用:

for (int iteration = 0; iteration < initialDistanceMatrix.length; iteration++) 

這保持您的所有索引爲零而不是混合它們。我只用這個代碼更改(和一個更小的測試用例)就得到了正確的答案。

+0

@ AndyN嗯,這種改變似乎並沒有解決我的問題。你能幫我理解你的改變如何影響算法嗎? 根據我的理解,向循環中添加另一個迭代不會改變每平方的數字計算方式。即使這樣,它也不會將特定列的解決方案從10更改爲8,因爲實際計算的任何內容都只是通過添加另一個迭代而改變。你在你的解決方案中說我不是「在第一個循環中正確地遍歷所有的頂點」,但是在最後添加迭代並不會改變開始。 – ngserdna

+0

@ngserna沒有循環遍歷第一個循環中的所有頂點,所以沒有檢查所有可能的中間頂點。第一個循環查看可能的中間頂點,它比'i'到'j'短。在這種情況下,你不考慮最後一個頂點。所以,例如,你並沒有考慮'Dik_Dkj'可以通過頂點15(k == 15) 。 說了這些,你可能仍然有一個錯誤,你如何產生我看不到的序列矩陣。你可能希望用一個預期的輸出來編寫一個更小的單元測試,並逐步瞭解如何構建序列矩陣。 – AndyN

+0

您可能還想看看[this]的路徑重構部分(https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm)。具體來說,看看更新距離時是如何計算下一個頂點的,而不是單獨設置for循環。 – AndyN