Preliminaries for Benelux Algorithm Programming Contest 2019 C. Canyon Crossing bfs按条件分层优化

很容易想到二分答案,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;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值