1631. 最小体力消耗路径 #并查集 #最短路径
题意
给定一二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子(row,col) 的高度。一开始你在最左上角的格子(0,0) ,且你希望去最右下角的格子(rows−1,columns−1) (下标从 0 开始)。每次可以往 上,下,左,右 四个方向之一移动,你想要找到耗费 体力 最小的一条路径。
一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。
分析
法一:Dijkstra求单源最短路径。从起点出发,四个方向,松弛其邻接的边,将能够松弛的顶点加入堆。其中顶点(x,y)松弛的条件,即为dis[x][y]>max(dis[u.i][u.j],diff),其中diff为(x,y)到(u.i,u.j)的边权。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| typedef struct Node{ int i, j, dis; bool operator < (const struct Node& others) const{ return dis > others.dis; } } node; class Solution { private: int n, m; int di[5] = {0, 1, 0, -1, 0}; int dj[5] = {0, 0, -1, 0, 1}; int dis[105][105]; public: int minimumEffortPath(vector<vector<int>>& heights) { n = heights.size(); m = heights[0].size(); memset(dis, 0x3f, sizeof(dis)); dis[0][0] = 0; priority_queue<node> myque; myque.push({0, 0, 0}); while(!myque.empty()){ node u = myque.top(); myque.pop(); if (u.dis != dis[u.i][u.j]) continue; for (int t = 1; t <= 4; t++){ int x = u.i + di[t], y = u.j + dj[t]; if(x < 0 || x >= n || y < 0 || y >= m) continue; int diff = abs(heights[u.i][u.j] - heights[x][y]); if(dis[x][y] > max(dis[u.i][u.j], diff)){ dis[x][y] = max(dis[u.i][u.j], diff); myque.push({x, y, dis[x][y]}); } } } return dis[n - 1][m - 1]; } };
|
法二:并查集。首先预处理,遍历矩阵中每个点,将每个点的四个方向的邻接点进行建边,边权为其两点间的差值。建立边集后,按边权从小到大排序边集,然后按此顺序依次将边中的点进行合并,直到起点与终点连通时,所对应的边的边权即为题目所求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| typedef struct Edge{ int u, v, w; bool operator < (const struct Edge& others) const { return w < others.w; } } edge; class Solution { private: int fa[10005]; int n, m; public: int findSet(int x){ if(x != fa[x]) fa[x] = findSet(fa[x]); return fa[x]; } int minimumEffortPath(vector<vector<int>>& heights) { n = heights.size(), m = heights[0].size(); vector<edge> E; for (int i = 0; i < (n * m); i++) fa[i] = i; for (int i = 0; i < n; i++){ for (int j = 0; j < m; j++){ int idx = i * m + j; if(i - 1 >= 0) E.push_back({idx, idx - m, abs(heights[i][j] - heights[i - 1][j])}); if(j - 1 >= 0) E.push_back({idx, idx - 1, abs(heights[i][j] - heights[i][j - 1])}); } } sort(E.begin(), E.end()); for(int i = 0; i < E.size(); i++){ int pu = findSet(E[i].u), pv = findSet(E[i].v); if(pu != pv) fa[pu] = pv; int st = findSet(0), ed = findSet(n * m - 1); if(st == ed) return E[i].w; } return 0; } };
|
1632. 矩阵转换后的秩 #并查集
题意
给你一个 m x n 的矩阵 matrix ,请你返回一个新的矩阵 answer ,其中 answer[row][col] 是 matrix[row][col] 的秩。
每个元素的 秩 是一个整数,表示这个元素相对于其他元素的大小关系,它按照如下规则计算:
样例

分析
好多题解我都没看懂QAQ,感谢@huanglin的代码帮我弄清这题的思路。
如果给定的矩阵并不存在一个相同的元素的话,那么只需要从小到大排序就能排出秩。但是题目中最主要的问题,在于同行、同列的相同元素,会共享同一个秩。
如何解决?首先应将矩阵中的所有元素进行排序,然后按该顺序遍历每个顶点。将其对应的行、列中相同的元素合并在一个并查集中,然后再用当前的最大的秩号去更新这个并查集的代表元素(满足同行、同列的相同元素共享同一个秩)。
如果该顶点不存在行列相同的元素,那么就从当前行列的元素最大的秩号+1(满足p<q ,那么rank(p)<rank(q))。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| class Solution { private: int n, m; int fatherIdx[500 * 500 + 5], fatherVal[500 * 500 + 5] = { 0 }; public: int findSet(int x) { if (x != fatherIdx[x]) fatherIdx[x] = findSet(fatherIdx[x]); return fatherIdx[x]; } void Union(int x, int y) { int px = findSet(x), py = findSet(y); if (px != py) fatherIdx[px] = py; } vector<vector<int>> matrixRankTransform(vector<vector<int>>& matrix) { n = matrix.size(); m = matrix[0].size(); vector< pair<int, int> > matrixVal; for (int i = 0; i < (n * m); i++) matrixVal.push_back({ matrix[i / m][i % m], i }); sort(matrixVal.begin(), matrixVal.end()); vector<int> toRow(n, -1), toCol(m, -1); for (int i = 0; i < (n * m); i++) fatherIdx[i] = i;
for (int pos = 0; pos < (n * m); pos++) { int idx = matrixVal[pos].second; int i = idx / m, j = idx % m; int val = 1; if (toRow[i] != -1) { int toIdx = i * m + toRow[i]; int toFatherIdx = findSet(toIdx); int toFatherVal = fatherVal[toFatherIdx]; if (matrix[i][j] == matrix[i][toRow[i]]) { Union(idx, toIdx); val = max(val, toFatherVal); } else val = max(val, toFatherVal + 1); } if (toCol[j] != -1) { int toIdx = toCol[j] * m + j; int toFatherIdx = findSet(toIdx); int toFatherVal = fatherVal[toFatherIdx]; if (matrix[i][j] == matrix[toCol[j]][j]) { Union(idx, toIdx); val = max(val, toFatherVal); } else val = max(val, toFatherVal + 1); } toRow[i] = j; toCol[j] = i; int curFatherIdx = findSet(idx); fatherVal[curFatherIdx] = val; } vector<vector<int>> res(n, vector<int>(m)); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { res[i][j] = fatherVal[findSet(i * m + j)]; } } return res; } };
|