很容易想到二分答案,bfs 进行 check。
关键是如何用bfs进行check。
由于每个点都有可能走重复,不好bfs。
我们可以按需要造桥数量进行bfs。
每个点至多访问一次,(因为后访问的点,造桥数量一定大于等于先访问的点)
判断下是否能在规定条件内到达对岸即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e3+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}
*/
int n,m,k,r;
int a[M][M];
int d[4][2]={1,0,0,1,-1,0,0,-1};
struct node{
int x,y;
};
bool vs[M][M];//某个点是否访问过,先访问的肯定优于后访问的(因为先访问需要造桥数量少)
bool bfs(int x)
{
queue<node>q[M];
memset(vs,0,sizeof(vs));
for(int i=1;i<=m;i++)q[a[n][i] < x ?1:0].push(node{n,i});
for(int i=0;i<=k;i++)//需要几个桥,可达的点
{
while(!q[i].empty())
{
node tp=q[i].front();
q[i].pop();
// cout<<i<<" "<<tp.x<<" "<<tp.y<<endl;
if(tp.x==1)return true;//可以在给定条件下到达顶部。
for(int j=0;j<4;j++)
{
int dx=tp.x+d[j][0],dy=tp.y+d[j][1];
if(dx<1||dx>n||dy<1||dy>m||vs[dx][dy])continue;//越界
vs[dx][dy]=true;
q[a[dx][dy]<x?i+1:i].push(node{dx,dy}); //到达的点是否需要造桥
}
}
}
return false;//桥造完也不能满足最低点大于等于x的条件
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j],r=max(a[i][j],r);
int l=0,ans;
while(l<=r)
{
int m=(l+r)/2;
//cout<<l<<" ---- "<<r<<" "<<m<<endl;
if(bfs(m))ans=m,l=m+1;
else r=m-1;
}
cout<<ans<<endl;
return 0;
}
也可以不分层,像下面这样搞,只有造桥数量更优才进行更新,。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e3+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}
*/
int n,m,k,r;
int a[M][M];
int d[4][2]={1,0,0,1,-1,0,0,-1};
struct node{
int x,y;
};
int vs[M][M];//某个点是否访问过,先访问的肯定优于后访问的(因为先访问需要造桥数量少)
bool bfs(int x)
{
queue<node>q;
memset(vs,60,sizeof(vs));
for(int i=1;i<=m;i++)vs[n][i]=a[n][i] < x ?1:0,q.push(node{n,i});
while(!q.empty())
{
node tp=q.front();
q.pop();
if(vs[tp.x][tp.y]>k)continue;
// cout<<vs[tp.x][tp.y]<<" "<<tp.x<<" "<<tp.y<<endl;
if(tp.x==1)return true;//可以在给定条件下到达顶部。
for(int j=0;j<4;j++)
{
int dx=tp.x+d[j][0],dy=tp.y+d[j][1];
if(dx<1||dx>n||dy<1||dy>m)continue;//越界
int z=vs[tp.x][tp.y]+(a[dx][dy]<x?1:0);
if(z<vs[dx][dy])vs[dx][dy]=z,q.push(node{dx,dy});
// cout<<"----------------- "<<z<<" "<<dx<<" "<<dy<<" "<<vs[tp.x][tp.y]<<" "<<vs[dx][dy]<<endl;
//到达的点 从当前点过去是否更优
}
}
return false;//桥造完也不能满足最低点大于等于x的条件
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j],r=max(a[i][j],r);
int l=0,ans;
while(l<=r)
{
int m=(l+r)/2;
// cout<<l<<" ---- "<<r<<" "<<m<<endl;
if(bfs(m))ans=m,l=m+1;
else r=m-1;
}
cout<<ans<<endl;
return 0;
}