给定一个矩阵A[m][n] ,矩阵上各点的值为移动到该点的代价,每次可以从该点的对角线或直线方向移动一格,求从点A[0][0]移动到点A[m-1][n-1]的最小代价。
比如矩阵,求从左上角的1移动到右下角的1的最小代价。
1 3 0 0 1 2
1 2 0 0 2 3
1 1 1 0 0 1
1 1 1 2 1 1
3 0 0 1 0 1
本题可以看成是带权重的有向图上单源最短路径问题,将棋盘上的点看成是一组节点集合。每一个点至多与其他八个点直接相连,,即点 u 发出的边至多为8,A[m][n]表示移动到该点的权重。因此可以用Dijkstra算法求解。
Dijkstra算法维持的一组关键信息是一组节点集合S,该集合中的每个点到源节点 s 的最短路径已经被找到。算法重复的从节点结合 V−S 中选择最短路径最小的的节点 u ,将u加入到集合S,然后对所有从u发出的边进行松弛。
Dis(G,w,s)
Inital_Single_Source(G,s)
s=空集
Q=G.V
while(Q!= 空集)
u=Extract_min(Q);
S.push(u)
for each vertex v in G.Adj[u]
Relax(u,v,w)
Inital_Single_Source(G,s)//初始化
for each v(v!=s) in G
v.dis = 无穷大
v.pre = NIL
//设初始点
s.dis = 0;
s.pre = -1;
Relax(u,v,w)
if(v.dis > u.dis + w(u,v))
v.dis > u.dis + w(u,v)
v.pre = u
#include
#include
using namespace std;
const int Max = 10000;
struct Node
{
int dist;
int pre;
};
void Init(Node* gNode, int count)
{
for (int i = 0; i < count; i++)
{
gNode[i].dist = Max;
gNode[i].pre = -1;
}
}
void Relax(Node* gNode, int** map, int u, int v, int node)
{
if (gNode[v].dist > gNode[u].dist + map[v / node][v % node])
{
gNode[v].dist = gNode[u].dist + map[v / node][v % node];
gNode[v].pre = u;
}
}
int main(void)
{
freopen("test.in", "r", stdin);
freopen("result.out", "w", stdout);
int hang,lie, i, j;
cin >> hang >> lie;//hang:行数,lie:列数
//存原始棋盘
int **map = new int*[lie];
for (i = 0; i < hang; i++)
map[i] = new int[lie];
for ( i = 0; i < hang; i++)
for (j = 0; j < lie; j++)
cin >> map[i][j];
for (i = 0; i < hang; i++)
{
for (j = 0; j < lie; j++)
cout << map[i][j]<<" ";
cout << endl;
}
int count = hang*lie;
Node * gNode = new Node[count];
int *S = new int[count];//集合S,保存被找到最短路径的结点置1,否则置0;集合Q为集合S的补集
//S[i]置为空
for (i = 0; i < count; i++)
S[i] = 0;
//Initial
Init(gNode, count);
gNode[0].dist = 0;
gNode[0].pre = -1;
int flag = 0;//检测Q是否为空
while (flag < count)//循环节点个数次
{
//find min
int min = Max;
int index = -1;
for (i = 0; i < count; i++)
{
if (S[i]==0 && gNode[i].dist < min )//S[i]未被加入集合中
{
min = gNode[i].dist;
index = i;
}
}
S[index] = 1;
flag++;
int col = index / lie;
int row = index % lie;
//对每个节点发出的每条边做松弛操作
if ((col - 1) >= 0)
{
Relax(gNode, map, index, index - lie, lie);
if ((row - 1) >= 0)
Relax(gNode, map, index, index - lie-1, lie);
if ((row+1)map, index, index - lie+1, lie);
}
if (col >= 0 && col < hang)
{
if ((row - 1) >= 0)
Relax(gNode, map, index, index - 1, lie);
if ((row + 1)map, index, index+ 1, lie);
}
if ((col + 1) < hang)
{
Relax(gNode, map, index, index + lie, lie);
if ((row - 1) >= 0)
Relax(gNode, map, index, index + lie - 1, lie);
if ((row + 1)map, index, index + lie + 1, lie);
}
}
int cost = gNode[count - 1].dist + map[0][0];//因为初始点也有权重
cout << "Min cost is " << cost << endl;
int path = count-1;
stack<int> stackPath;
while (path != 0)
{
stackPath.push(path);
path = gNode[path].pre;
}
stackPath.push(0);
while (!stackPath.empty())
{
cout << stackPath.top()<< " ";
stackPath.pop();
}
}
输入实例:
5 6
1 3 0 0 1 2
1 2 0 0 2 3
1 1 1 0 0 1
1 1 1 2 1 1
3 0 0 1 0 1
输出:
1 3 0 0 1 2
1 2 0 0 2 3
1 1 1 0 0 1
1 1 1 2 1 1
3 0 0 1 0 1
Min cost is 5
0 7 8 15 22 29 (行优先存储)