poj 2110 Mountain Walking 枚举+bfs

题意:

给一个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;	
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值