cf1064d Labyrinth

传送门
题意:给定一个图,图中有一些能走和不能走的点。走路的过程中,上下走无限制,左右走有1的花费。给定 x , y x,y x,y,向左花费不超过 x x x,向右不超过 y y y。求最多能够到达多少点。

从起点 s s s出发到某一个点 t t t,我们考虑如何最小化左右行走的花费。
假设我们向左走 p p p步,向右走 q q q步,那么一定有:
s . x − p + q = t . x ⇔ p − q = s . x − t . x s.x-p+q=t.x \Leftrightarrow p-q=s.x-t.x s.xp+q=t.xpq=s.xt.x
也就是说 p p p q q q的差是一定的。也就是说,当我们保证了 p p p最小时, q q q也一定是最小的。反过来 q q q最小时, p p p也一定是最小的。于是,我们如果可以保证它们的和最小,它们就都一定取到最小。也就是沿着最短路走。上 01 b f s 01bfs 01bfs即可。

本质是我们通过 01 b f s 01bfs 01bfs改变了 b f s bfs bfs的顺序,从而每次都用最优点去更新其它点,使得每个点第一次被更新就得到最优解。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e3+10;
int n,m,ans=0,M[maxn][maxn],vis[maxn][maxn];
struct point{
	int x,y,resl,resr;
	point(int X=0,int Y=0,int RESL=0,int RESR=0){x=X,y=Y,resl=RESL,resr=RESR;}
	inline bool check(){
		return 1<=x&&x<=n&&1<=y&&y<=m&&(!vis[x][y])&&(M[x][y]=='.')&&(resl>=0)&&(resr>=0);
	}
	friend inline point operator+(const point &a,const point &b){
		return point(a.x+b.x,a.y+b.y,a.resl+b.resl,a.resr+b.resr);
	}
}S,d[4];
inline int get_ch(){
	char ch=getchar();
	while(ch!='.'&&ch!='*') ch=getchar();
	return ch;
}
inline int read(){
	int x=0;char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return x;
}
inline void bfs(){
	deque<point> Q;++ans;
	Q.push_front(S),vis[S.x][S.y]=1;
	while(!Q.empty()){
		point u=Q.front();Q.pop_front();
		for(int i=0;i<4;++i){
			point v=u+d[i];
			if(v.check()){
				vis[v.x][v.y]=1,++ans;
				(i&1)?Q.push_back(v):Q.push_front(v);
			}
		}
	}
}
int main(){
	n=read(),m=read();
	S.x=read(),S.y=read(),S.resl=read(),S.resr=read();
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			M[i][j]=get_ch();
	d[0]=point(1,0,0,0),d[1]=point(0,1,0,-1);
	d[2]=point(-1,0,0,0),d[3]=point(0,-1,-1,0);
	bfs(),printf("%d\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值