题目链接:
题目描述:
解法
注意:砍树要从低到高砍。
砍掉1,从1到5到2
砍掉2,从2到5到3
砍掉3,从3到5到2到6到4
砍掉4,从4到6到5
砍掉5,从5到6
砍掉6
变成若干个迷宫问题了。
把所有的最小值求出来然后加起来。
但是有个问题,你怎么知道砍树的顺序呢?
所以我们要先找到砍树的顺序,弄个二维数组先存一下下标和内容,然后按照内容由小到大排序。
C++ 算法代码:
class Solution {
int m, n; // 森林的行数和列数
public:
int cutOffTree(vector<vector<int>>& f) {
m = f.size(), n = f[0].size();
// 1. 准备工作:找出所有需要砍的树,并按树的高度排序
vector<pair<int, int>> trees;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
if (f[i][j] > 1) // 树的高度大于1才需要砍
trees.push_back({i, j});
// 按照树的高度从小到大排序
sort(trees.begin(), trees.end(),
[&](const pair<int, int>& p1, const pair<int, int>& p2) {
return f[p1.first][p1.second] < f[p2.first][p2.second];
});
// 2. 按照顺序砍树
int bx = 0, by = 0; // 起始位置(0,0)
int ret = 0; // 总步数
for (auto& [a, b] : trees) {
// 计算从当前位置到下一棵树的最短步数
int step = bfs(f, bx, by, a, b);
if (step == -1) // 如果无法到达,返回-1
return -1;
ret += step; // 累加步数
bx = a, by = b; // 更新当前位置
}
return ret;
}
bool vis[51][51]; // 访问标记数组
int dx[4] = {0, 0, 1, -1}; // 四个方向的x偏移量
int dy[4] = {1, -1, 0, 0}; // 四个方向的y偏移量
// BFS计算从起点(bx,by)到终点(ex,ey)的最短步数
int bfs(vector<vector<int>>& f, int bx, int by, int ex, int ey) {
if (bx == ex && by == ey) // 如果起点就是终点,返回0步
return 0;
queue<pair<int, int>> q;
memset(vis, 0, sizeof vis); // 清空访问标记
q.push({bx, by});
vis[bx][by] = true;
int step = 0;
while (q.size()) {
step++;
int sz = q.size();
// 处理当前层的所有节点
while (sz--) {
auto [a, b] = q.front();
q.pop();
// 尝试四个方向
for (int i = 0; i < 4; i++) {
int x = a + dx[i], y = b + dy[i];
// 检查新位置是否合法
if (x >= 0 && x < m && y >= 0 && y < n &&
f[x][y] != 0 && !vis[x][y]) { // 0表示不能走的障碍物
// 找到终点,返回当前步数
if (x == ex && y == ey)
return step;
q.push({x, y});
vis[x][y] = true;
}
}
}
}
return -1; // 无法到达终点
}
};