题意:
给一个n*n的矩阵,要从左上角走到右下角,使经过数字的最大数与最小数的差最小。
分析:
一开始想到了二分这个差,然后判断是否存在路径,每次只知道差的话深搜每次搜索要记录沿途的最大值和最小值会tle,广搜的话如果节点只记录x,y坐标,搜索中存在要重新访问以前访问过节点的情况,比如一开始(1,1)->(1,2)->(2,2),如果(2,1)这个点的值更合适,最优访问路径(1,1)->(2,1)->(2,2),也就是(2,2)要被重新访问,不满足广搜每个节点只访问一次的原则,只有增加节点维度每个节点记录x,y坐标和到达它经过的最小最大值,显然不好。后来了解到可以加大枚举,不仅枚举差,还枚举路径上的最大值,这样每次路径上的最大最小值就确定了,可以广搜。
//poj 2110
//sep9
#include <iostream>
#include <queue>
using namespace std;
const int maxN=128;
struct Node
{
int x,y;
};
int g[maxN][maxN];
int vis[maxN][maxN];
int dirx[4]={0,0,-1,1};
int diry[4]={-1,1,0,0};
int n,diff,min_hight,max_hight;
queue<Node> q;
bool pass(int low,int high)
{
memset(vis,0,sizeof(vis));
Node a;
a.x=1,a.y=1;
if(g[1][1]>high||g[1][1]<low)
return false;
while(!q.empty()) q.pop();
q.push(a);
vis[1][1]=1;
while(!q.empty()){
Node t=q.front();q.pop();
int x=t.x,y=t.y;
for(int k=0;k<4;++k){
int nx=x+dirx[k];
int ny=y+diry[k];
if(nx>=1&&nx<=n&&ny>=1&&ny<=n&&vis[nx][ny]==0&&g[nx][ny]<=high&&g[nx][ny]>=low){
Node a;
a.x=nx,a.y=ny;
q.push(a);
vis[nx][ny]=1;
if(nx==n&&ny==n) return true;
}
}
}
return false;
}
bool work(int mid)
{
for(int high=min_hight;high<=max_hight;++high){
int low=high-mid;
if(pass(low,high))
return true;
}
return false;
}
int main()
{
scanf("%d",&n);
min_hight=INT_MAX;
max_hight=INT_MIN;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j){
scanf("%d",&g[i][j]);
min_hight=min(min_hight,g[i][j]);
max_hight=max(max_hight,g[i][j]);
}
int ans,l=0,r=max_hight+1,mid;
while(l<r){
mid=(l+r)/2;
if(work(mid)){
r=mid;
ans=mid;
}else
l=mid+1;
}
printf("%d",ans);
return 0;
}