/// <summary> /// Computes the lowest cost path, in recursive manner. /// </summary> /// <returns>Calculate the lowest cost path.</returns> /// <param name="matrix">Cost matrix.</param> /// <param name="row">For specified row.</param> /// <param name="column">For specified column.</param> TraversalPath ComputeLowestCostPath(CostMatrix matrix, int row, int column) { TraversalPath lowestPath; if (column == 0) { //If we have reached the first column, we send back a new path instance lowestPath = new TraversalPath(matrix.NumberOfColumns); } else { //Calculate lowest path for one-row up from previous column var rowUpCostPath = ComputeLowestCostPath(matrix, matrix.RowUp(row), column - 1); //Calculate lowest path for current row from previous column var rowNextCostPath = ComputeLowestCostPath(matrix, row, column - 1); //Calculate lowest path for one-row down from previous column var rowDownCostPath = ComputeLowestCostPath(matrix, matrix.RowDown(row), column - 1); //and find the lowest path from all three possible moves lowestPath = rowUpCostPath; if (rowNextCostPath < lowestPath) { lowestPath = rowNextCostPath; } if (rowDownCostPath < lowestPath) { lowestPath = rowDownCostPath; } } //once we have the lowest possible move (or cost) we append that to current path //and also validate if it reaches max possible cost (if it does we invalidate the //path to abadon it) var nextPathTraversalCost = lowestPath.TotalCost + matrix[row, column]; if (nextPathTraversalCost <= m_maxCost) { lowestPath.Append(row, matrix[row, column]); } else { lowestPath.Invalidate(); } return(lowestPath); }
/// <summary> /// Applies strategy/algorithm for calculating lowest-cost path across /// the specified cost-matrix. /// </summary> /// <returns>The lowest traversal path.</returns> /// <param name="matrix">The cost matrix.</param> public override TraversalPath GetLowestTraversalPath(CostMatrix matrix) { //create a matrix that will cache traversal-cost for each cell TraversalPath[,] cachedPaths = new TraversalPath[matrix.NumberOfRows, matrix.NumberOfColumns]; //in this case we first go column by column for (int column = 0; column < matrix.NumberOfColumns; column++) { //and calculate lowest traversal cost for that particular cell (each row in column) for (int row = 0; row < matrix.NumberOfRows; row++) { //initilize traversal path cachedPaths[row, column] = new TraversalPath(column + 1); //get cost for current cell var currentCellCost = matrix[row, column]; int traversalCost; if (column == 0) { //as it is first column, traversal-cost is same as current cell traversalCost = currentCellCost; } else { //get adjacent up row index var rowUpIndex = matrix.RowUp(row); //get adjacent down row index var rowDownIndex = matrix.RowDown(row); //get traversal cost for adjacent up-row for previous column var traversalPathFromUpRow = cachedPaths[rowUpIndex, column - 1]; //get traversal cost from current row for previous column var traversalPathFromPrevRow = cachedPaths[row, column - 1]; //get traversal cost from adjacent down-row for previous column var traversalPathFromDownRow = cachedPaths[rowDownIndex, column - 1]; //and find the lowest path from all three possible moves var lowestTraversalPath = traversalPathFromUpRow; if (traversalPathFromPrevRow < lowestTraversalPath) { lowestTraversalPath = traversalPathFromPrevRow; } if (traversalPathFromDownRow < lowestTraversalPath) { lowestTraversalPath = traversalPathFromDownRow; } //once we have the lowest traversal cost we copy that onto current cell cache TraversalPath.Copy(lowestTraversalPath, cachedPaths[row, column]); //and calculate total traversalCost = lowestTraversalPath.TotalCost + currentCellCost; } //if traversal cost is valid, we append that current cell cache if (traversalCost <= m_maxCost) { cachedPaths[row, column].Append(row, currentCellCost); } //else we abadon the path (that is invalidate the cell) else { cachedPaths[row, column].Invalidate(); } } } //With the cache grid ready and initialized, we find the lowest cost by //traversing TraversalPath lowestCostPath = null; if (matrix.NumberOfColumns >= 1) { for (int row = 0; row < matrix.NumberOfRows; row++) { var costPath = cachedPaths[row, matrix.NumberOfColumns - 1]; if (lowestCostPath == null || costPath <= lowestCostPath) { lowestCostPath = costPath; } } } return(lowestCostPath ?? new TraversalPath(0)); }