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