该题的大致题意:
给你一个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;
}