传送门
题意:给定一个图,图中有一些能走和不能走的点。走路的过程中,上下走无限制,左右走有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.x−p+q=t.x⇔p−q=s.x−t.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);
}