原题链接:675. 为高尔夫比赛砍树
solution:
广度优先搜索,首先将所有点按高度从小到大进行排序,每两个点更新一次最大距离。
时间复杂度O(m^2 + n^2)
bfs函数返回start到end的最短距离
class Solution {
public:
vector<vector<int>> g;
int m,n;
const int INF = 0x3f3f3f3f;
struct Tree {
int x,y,h; //坐标和高度
bool operator< (const Tree& t) const { //重载小于号
return h < t.h;
}
};
int bfs(struct Tree start,struct Tree end) {
if(start.x == end.x && start.y == end.y) return 0; //相等返回0
queue<Tree> que;
vector<vector<int>> dist(m, vector<int> (n, INF)); //初始化距离为无穷大
que.push(start);
int dx[] = {-1,0,1,0},dy[] = {0,-1,0,1};
dist[start.x][start.y] = 0; //起点距离为0
while(que.size()) {
auto t = que.front();
que.pop();
for(int i = 0;i < 4;i++) {
int a = t.x + dx[i],b = t.y + dy[i];
if(a >= 0 && a < m && b >= 0 && b < n && g[a][b]) {
if(dist[a][b] > dist[t.x][t.y] + 1) {
dist[a][b] = dist[t.x][t.y] + 1;
if(a == end.x && b == end.y) return dist[a][b];
que.push({a,b});
}
}
}
}
return -1;
}
int cutOffTree(vector<vector<int>>& forest) {
g = forest;
m = forest.size(),n = forest[0].size(); //m行n列
vector<Tree> trees;
for(int i = 0;i < m;i++)
for(int j = 0;j < n;j++) {
if(g[i][j] > 1) trees.push_back({i,j,g[i][j]}); //保存每个高度大于1的点
}
sort(trees.begin(),trees.end()); //按高度从小到大排序
Tree last = {0,0,0};
int path = 0; //保存砍树最短距离
for(int i = 0;i < trees.size();i++) {
int t = bfs(last,trees[i]); //t保存last到trees[i]的最短距离
if(t == -1) return -1; //如果t == -1,表示无法抵达
path += t;
last = trees[i];
}
return path;
}
};