📌  相关文章
📜  允许左,右,下和上移动的最小成本路径

📅  最后修改于: 2021-04-26 08:20:39             🧑  作者: Mango

给定一个二维网格,该网格的每个像元都包含整数成本,代表通过该像元所要经过的成本,我们需要找到一条从左上角像元到右下角像元的路径,从而使总成本最小。
注:假定输入矩阵中不存在负成本周期。
这个问题是下面的问题的延伸。
最小费用路径,允许左右移动。
在先前的问题中,只允许向右和向下移动,但在此问题中,我们被允许从底部,上,右和左移动,即在所有四个方向上移动。
例子:

下图给出了成本网格,从左上角到右下角的最小成本为327(= 31 + 10 + 13 + 47 + 65 + 12 + 18 + 6 + 33 + 11 + 20 + 41 + 20)最低费用路径以绿色显示。

使用类似于先前问题的动态编程无法解决此问题,因为此处的当前状态不仅取决于右侧和底部单元,而且还取决于左侧和上部单元。我们使用dijkstra的算法解决了这个问题。网格的每个像元代表一个顶点,相邻像元代表相邻的顶点。我们不从这些单元格中生成一个明确的图形,而是将使用dijkstra算法中的矩阵。
在下面的代码中,使用了Dijkstra算法的实现。更改以下实现的代码以应对矩阵表示的隐式图。还请参见下面的代码中dx和dy数组的使用,这些数组用于简化访问每个像元的相邻顶点的过程。

C++
// C++ program to get least cost path in a grid from
// top-left to bottom-right
#include 
using namespace std;
  
#define ROW 5
#define COL 5
  
// structure for information of each cell
struct cell
{
    int x, y;
    int distance;
    cell(int x, int y, int distance) :
        x(x), y(y), distance(distance) {}
};
  
// Utility method for comparing two cells
bool operator<(const cell& a, const cell& b)
{
    if (a.distance == b.distance)
    {
        if (a.x != b.x)
            return (a.x < b.x);
        else
            return (a.y < b.y);
    }
    return (a.distance < b.distance);
}
  
// Utility method to check whether a point is
// inside the grid or not
bool isInsideGrid(int i, int j)
{
    return (i >= 0 && i < COL && j >= 0 && j < ROW);
}
  
// Method returns minimum cost to reach bottom
// right from top left
int shortest(int grid[ROW][COL], int row, int col)
{
    int dis[row][col];
  
    // initializing distance array by INT_MAX
    for (int i = 0; i < row; i++)
        for (int j = 0; j < col; j++)
            dis[i][j] = INT_MAX;
  
    // direction arrays for simplification of getting
    // neighbour
    int dx[] = {-1, 0, 1, 0};
    int dy[] = {0, 1, 0, -1};
  
    set st;
  
    // insert (0, 0) cell with 0 distance
    st.insert(cell(0, 0, 0));
  
    // initialize distance of (0, 0) with its grid value
    dis[0][0] = grid[0][0];
  
    // loop for standard dijkstra's algorithm
    while (!st.empty())
    {
        // get the cell with minimum distance and delete
        // it from the set
        cell k = *st.begin();
        st.erase(st.begin());
  
        // looping through all neighbours
        for (int i = 0; i < 4; i++)
        {
            int x = k.x + dx[i];
            int y = k.y + dy[i];
  
            // if not inside boundary, ignore them
            if (!isInsideGrid(x, y))
                continue;
  
            // If distance from current cell is smaller, then
            // update distance of neighbour cell
            if (dis[x][y] > dis[k.x][k.y] + grid[x][y])
            {
                // If cell is already there in set, then
                // remove its previous entry
                if (dis[x][y] != INT_MAX)
                    st.erase(st.find(cell(x, y, dis[x][y])));
  
                // update the distance and insert new updated
                // cell in set
                dis[x][y] = dis[k.x][k.y] + grid[x][y];
                st.insert(cell(x, y, dis[x][y]));
            }
        }
    }
  
    // uncomment below code to print distance
    // of each cell from (0, 0)
    /*
    for (int i = 0; i < row; i++, cout << endl)
        for (int j = 0; j < col; j++)
            cout << dis[i][j] << " ";
    */
    // dis[row - 1][col - 1] will represent final
    // distance of bottom right cell from top left cell
    return dis[row - 1][col - 1];
}
  
// Driver code to test above methods
int main()
{
    int grid[ROW][COL] =
    {
        31, 100, 65, 12, 18,
        10, 13, 47, 157, 6,
        100, 113, 174, 11, 33,
        88, 124, 41, 20, 140,
        99, 32, 111, 41, 20
    };
  
    cout << shortest(grid, ROW, COL) << endl;
    return 0;
}


Java
// Java program to get least cost path 
// in a grid from top-left to bottom-right
import java.io.*;
import java.util.*;
  
class GFG{
      
static int[] dx = { -1, 0, 1, 0 };
static int[] dy = { 0, 1, 0, -1 };
static int ROW = 5;
static int COL = 5;
  
// Custom class for representing
// row-index, column-index &
// distance of each cell
static class Cell
{
    int x;
    int y;
    int distance;
      
    Cell(int x, int y, int distance) 
    {
        this.x = x;
        this.y = y;
        this.distance = distance;
    }
}
  
// Custom comparator for inserting cells 
// into Priority Queue
static class distanceComparator 
  implements Comparator
{
    public int compare(Cell a, Cell b)
    {
        if (a.distance < b.distance)
        {
            return -1;
        }
        else if (a.distance > b.distance)
        {
            return 1;
        }
        else {return 0;}
    }
}
  
// Utility method to check whether current
// cell is inside grid or not
static boolean isInsideGrid(int i, int j)
{
    return (i >= 0 && i < ROW &&
            j >= 0 && j < COL);
}
  
// Method to return shortest path from 
// top-corner to bottom-corner in 2D grid
static int shortestPath(int[][] grid, int row, 
                                      int col)
{
    int[][] dist = new int[row][col];
      
    // Initializing distance array by INT_MAX 
    for(int i = 0; i < row; i++)
    {
        for(int j = 0; j < col; j++)
        {
            dist[i][j] = Integer.MAX_VALUE;
        }
    }
      
    // Initialized source distance as
    // initial grid position value
    dist[0][0] = grid[0][0];
      
    PriorityQueue pq = new PriorityQueue(
                  row * col, new distanceComparator());
                    
    // Insert source cell to priority queue
    pq.add(new Cell(0, 0, dist[0][0]));
    while (!pq.isEmpty())
    {
        Cell curr = pq.poll();
        for(int i = 0; i < 4; i++)
        {
            int rows = curr.x + dx[i];
            int cols = curr.y + dy[i];
              
            if (isInsideGrid(rows, cols))
            {
                if (dist[rows][cols] > 
                    dist[curr.x][curr.y] + 
                    grid[rows][cols])
                {
                      
                    // If Cell is already been reached once,
                    // remove it from priority queue
                    if (dist[rows][cols] != Integer.MAX_VALUE)
                    {
                        Cell adj = new Cell(rows, cols, 
                                       dist[rows][cols]);
                                         
                        pq.remove(adj);
                    }
                      
                    // Insert cell with updated distance 
                    dist[rows][cols] = dist[curr.x][curr.y] +
                                       grid[rows][cols];
                                         
                    pq.add(new Cell(rows, cols, 
                               dist[rows][cols]));
                }
            }
        }
    }
    return dist[row - 1][col - 1];
}
  
// Driver code
public static void main(String[] args) 
throws IOException
{
    int[][] grid = { { 31, 100, 65, 12, 18 },
                     { 10, 13, 47, 157, 6 },
                     { 100, 113, 174, 11, 33 },
                     { 88, 124, 41, 20, 140 },
                     { 99, 32, 111, 41, 20 } };
                       
    System.out.println(shortestPath(grid, ROW, COL));
}
}
  
// This code is contributed by jigyansu


输出:

327