算法分析
题目大意:n*m的矩阵,每个格子上有一个权值。求一条(1,1)到(n,m)的路径,使
路径上权值的最小值最大。
【样列输入】forest.in
2 2
7 5
3 4
【样列输出】forest.out
4
解法:本题原本是可以用SPFA做的,但是由于出题的data是专门卡SPFA的,所以这
题只能二分答案。
二分答案的方法是:
先把所有权值进行排序,找到中间值,进行广搜看中间值是否有资格成为路径上的权
值最小值,如果成立,在右半区间重复上述操作,否则,在左半区间重复上述操作。
二分答案后,它检验的办法之神奇,用广搜检验。 (然而考试的时候直接想的是用深度优先搜索发现标记不了)
时间复杂度为o(nmlog2(nm));
提示:二分答案的时候没有必要排序,可以直接以min(A[1][1],A[N][M])作为下界,
上界可以在读入的时候取个最大值
代码实现
话不多说,直接上代码。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
int N,M;
int a[maxn][maxn];
const int size=maxn*maxn;
int q[size][2],head,tail;
bool V[maxn][maxn];
void pb(int x,int y){
q[++tail][0]=x,q[tail][1]=y;
V[x][y]=true;;
}
bool check(int x){
const int dir[4][2]={-1,0,1,0,0,1,0,-1};
memset(V,0,sizeof(V));
head=tail=0,pb(1,1);
while(head<tail){
int sx=q[++head][0],sy=q[head][1];
for(int i=0;i<4;i++){
int tx=sx+dir[i][0];
int ty=sy+dir[i][1];
if(tx<1||ty<1||tx>N||ty>M) continue;
if(V[tx][ty]||a[tx][ty]<x) continue;
pb(tx,ty);
}
}
return V[N][M];
}
int main(){
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
scanf("%d",&a[i][j]);
int ans;
int lft=-1000000000,rgt=min(a[1][1],a[N][M]),mid;
while(lft<=rgt){
mid=(lft+rgt)>>1;
if(check(mid)) ans=mid,lft=mid+1;else rgt=mid-1;
}
printf("%d",ans);
return 0;
}
总之,这应该能算是二分答案里的一股清流了。
如有不对的地方请大家多多指正,谢谢。