Sicily 1321. Robot 解题报告
1321_Robot
题目链接:
题目大意:
给一个矩阵,每一个点上面的数字表示走到该点需要的花费,找出给定起点到终点的最小总花费
思路:
每个格子看作一个结点,花费可以看作从上一个点走到这个点的路程,那么这道题就是典型的最短路径问题,可以用Dijkstra算法解决。一开始直接套用整个算法,将每个新的结点加入到集合S中的时候,更新所有不在集合中的结点的最短路径并排序以便下一次找出路径最短的结点,结果超时。 这里使用了优先队列q来优化,q里面放入每次可以加入到集合S里面的结点。整个流程类似Dijkstra算法,需要注意的地方是这里每次将一个结点加入S时只是简单的将相邻的4个结点放入到候选队列q中,所以q里面可能会出现重复的或者已经找到的结点,所以每次在队列中先将顶部已经完成的结点去掉。
代码:
#include <iostream> #include <queue> using namespace std; class Point { public: int x; int y; int distance; Point(int xx = 0, int yy = 0, int dd = 0) { x = xx; y = yy; distance = dd; } friend bool operator<(const Point &p1, const Point &p2) { //重载小于号这样优先队列默认为最小堆 return p1.distance > p2.distance; } }; int move_x[4] = { -1, 1, 0, 0 }; //上下左右 int move_y[4] = { 0, 0, -1, 1 }; int main() { int numTestcases; cin >> numTestcases; int numRow, numCol; int matrix[101][101]; //记录每个点的油耗 int start_x, start_y, end_x, end_y; //出发点和目标点坐标 bool included[101][101]; //Dijkstra算法里面的集合S,里面的每个结点到源结点的最短路径已经找到 while (numTestcases--) { cin >> numRow >> numCol; for (int row = 1; row <= numRow; ++row) { for (int col = 1; col <= numCol; ++col) { cin >> matrix[row][col]; included[row][col] = false; } } cin >> start_x >> start_y >> end_x >> end_y; // included[start_x][start_y] = true; //将源结点放入集合中 priority_queue<Point> q; //放入目前最有可能加入到集合S中的点 q.push(Point(start_x, start_y, matrix[start_x][start_y])); while (!(q.top().x == end_x && q.top().y == end_y)) { //队列顶部为目标时停止,这时候该点的distance值已经是最短路径,并准备放入到集合S中,停止循环并输出即可 while (included[q.top().x][q.top().y]) { q.pop(); } //每次取出离集合S距离最近的一个点加入到S中 Point cur = q.top(); included[cur.x][cur.y] = true; for (int i = 0; i < 4; ++i) { int x = cur.x + move_x[i]; int y = cur.y + move_y[i]; if (x >= 1 && x <= numRow && y >= 1 && y <= numCol && !included[x][y]) q.push(Point(x, y, cur.distance + matrix[x][y])); } } cout << q.top().distance << endl; } return 0; }