向右或者向下移动的话,就能用dp,这里是四个方向,只能用图来做。
思路:dijkstra
时间复杂度O((M+N)logM),其中 N 和 M 分别是图中的点数(nm)和边数 (4n*m)
我们可以将数组建模成一个包含 n * m 个节点和不超过 4 * m * n 条边的有向图 G。图 G 中的每一个节点表示数组 中的一个位置,它会向不超过 4 个相邻的节点各连出一条边,边的权值要么为 0(移动方向与箭头方向一致),要么为 1(移动方向与箭头方向不一致);
我们在图 G 上使用一种最短路算法,求出从 (0,0) 到 (m - 1, n - 1 的最短路,即可得到答案。
难点:方向怎么判断一致?
题目里的1 2 3 4对应(i+1)分别对应右左下上
int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; // 遍历到i时得到新位置(xx, yy) ,如果i + 1 == grid[x][y]则表示方向一致
class Solution {
public:
int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; //
using PII = pair<int, int>; //first为距离, second为位置
int minCost(vector<vector<int>>& grid) {
int n = grid.size(), m = grid[0].size();
vector<int> dis(n * m, INT_MAX);
vector<int> vis(n * m, false);
dis[0] = 0;
priority_queue<PII, vector<PII>, greater<PII>> pq;
pq.emplace(0, 0);
while (!pq.empty()) {
auto [dis, pos] = pq.top();
pq.pop();
if (vis[pos]) continue;
vis[pos] = true;
int x = pos / m;
int y = pos % m;
for (int i = 0; i < 4; ++i) {
int xx = x + dir[i][0];
int yy = y + dir[i][1];
int newpos = xx * m + yy;
int _dis = dis + (grid[x][y] != i + 1);
if (xx >= 0 && xx < n && yy >= 0 && yy < m && d[newpos] > _dis) {
dis[newpos] = _dis;
pq.emplace(dis[newpos], newpos);
}
}
}
return dis[n * m - 1];
}
};