题意:
给一个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; }
时间: 2024-10-07 00:27:35