该题的大致题意:
给你一个N * N的海拔分布图, 此时农民John在(1,1)处, 而他的度假小屋在(N,N)处, 现在他想要从(1,1)处
找出一条到达(N,N)处的路径,这条路径应该满足这样的要求:最高海拔和最低海拔的差值最小。并且John只
能向北,向南,向东,向西走。
我们能很轻易的想到要用搜索去找到这样一条路径,但是搜索一般是盲目的搜(换句话说,搜索会找到从(1,1)
到(N,N)的所有路径),它并不能找到我们想要的路径。 但是我们可以给搜索加上条件,就能找到我们想要的
路径了。
可以想到限制搜索的范围,我们可以枚举一个最高海拔,一个最低海拔。让搜索在这个范围内进行搜索,如果
能达到终点,说明该次搜索是有效的。
以上,我们能想到可以二分找到一个海拔差值,然后结合这个值和海拔总范围不断枚举一个最高海拔和最低
海拔。接着我们去搜索看能不能找到一条合法的路径。在不断枚举并搜索的过程中,只要有一次枚举的最高
海拔和最低海拔可以找到一条合法路径,说明这次二分的海拔差值是有效的,但是这并不是我们想要的(因为
这个差值可能不是最小的),所以我们需要缩小二分的右区间,继续寻找最小的海拔差值。否则的话我们就增
大左区间,直到左区间大于右区间
代码如下:
#include<stdio.h> #include<string.h> #include<queue> using namespace std; const int INF = 110; struct node { int x, y; }; int data[INF + 5][INF + 5]; //存地图 int bfs(int low, int high); //广搜,看能否在海拔范围为low,high中找到一条合法路径 int judge(int diff); //判断这个差值是否有效 int BinarySearch(int left, int right); //二分的过程 int dir[4][2] = {-1,0,0,-1,1,0,0,1}; //广搜的方向 int vis[INF + 5][INF + 5] = {0}; //用来在标记已经搜索到的点 int N; /* 5 1 1 3 6 8 1 2 2 5 5 4 4 0 3 3 8 0 2 3 4 4 3 0 2 1 */ int main() { scanf("%d", &N); for(int i = 1; i <= N ;i++) { for(int j = 1; j <= N; j++) scanf("%d", &data[i][j]); } int result = BinarySearch(0,INF); printf("%d\n", result); return 0; } int BinarySearch(int left, int right) { while(left <= right) { int mid = (left + right) / 2; if(judge(mid) == 1) { right = mid - 1; } else { left = mid + 1; } } return left; } int judge(int diff) { for(int i = 0 ; i + diff <= INF ;i++) { if(bfs(i, i + diff) == 1) { return 1; } } return 0; } int bfs(int low, int high) { memset(vis, 0, sizeof(vis)); node start; start.x = 1; start.y = 1; //广搜的起点 if(!(data[1][1] >= low && data[1][1] <= high)) return 0; queue <node> que; que.push(start); vis[1][1] = 1; while(!que.empty()) { node now = que.front(); que.pop(); if(now.x == N && now.y == N) return 1; for(int i = 0 ; i < 4; i++) { int nx = now.x + dir[i][0]; int ny = now.y + dir[i][1]; if(nx >= 1&& nx <= N && ny >= 1 && ny <= N && data[nx][ny] >= low && data[nx][ny] <= high && vis[nx][ny] == 0) { vis[nx][ny] = 1; node temp;temp.x = nx; temp.y = ny; que.push(temp); } } } return 0; }