当前位置: 代码迷 >> 综合 >> poj 2110 Mountain Walking 枚举+bfs
  详细解决方案

poj 2110 Mountain Walking 枚举+bfs

热度:97   发布时间:2024-01-19 05:40:35.0

题意:

给一个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;}elsel=mid+1;}printf("%d",ans);	return 0;	
}