分析
看到题目所求的是一个最大差值,很快想到二分答案,对于一个二分到的 \(mid\),我们枚举满足要求的最小值和最大值,表示我们路径只能经过权值在二者之间的点,这样走一个 \(dfs\),用 \(vis\) 数组判断起点终点是否连通就可以了。
这样二分的正确性也容易证明了,当一个答案可行时,更大的答案只会增加可行的点的位置,所以满足二分答案的性质,这样此题就解决了。
代码(将枚举放在前面,效果是一样的)
#include<bits/stdc++.h>
using namespace std;
inline void read(int &res){
char c;
int f=1;
res=0;
c=getchar();
while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
while(c>=‘0‘&&c<=‘9‘)res=(res<<1)+(res<<3)+c-48,c=getchar();
res*=f;
}
int n;
int mp[105][105];
int vis[105][105];
int ans=1e9;
void dfs(int x,int y,int l,int r){
if(mp[x][y]>r||mp[x][y]<l)return;//不满足范围
if(vis[x][y])return;//到达过
vis[x][y]=1;
dfs(x+1,y,l,r);
dfs(x-1,y,l,r);
dfs(x,y+1,l,r);
dfs(x,y-1,l,r);
return;
}
int main()
{
read(n);
for(int i=0;i<=n;i++)mp[i][0]=mp[i][n+1]=mp[0][i]=mp[n+1][i]=-1;//处理边界
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
read(mp[i][j]);
}
}
for(int i=0;i<=110;i++){//枚举最小值
int l=i,r=110;//二分答案
while(l<=r){
int mid=(l+r)>>1;
memset(vis,0,sizeof(vis));
dfs(1,1,i,mid);
if(vis[n][n]){
ans=min(ans,mid-i);
r=mid-1;
}
else l=mid+1;
}
}
cout<<ans;
return 0;
}