1 条题解
-
0
题解
思路分析
「推箱子」的离线判定问题。Bessie 能否把箱子推到目标格,本质上是判断在合法走动、推箱的规则下的可达状态。做法分为三步:
- Tarjan + DFS 找出 Bessie 可自由行走的区域:将地图看成图,把空地构成的连通块缩点,得到 Bessie 在不推箱子时可以随意往返的区域。
- 从起点 BFS 找到首个推动方向:若 Bessie 无法绕到箱子旁边,则直接不可行;否则记录初始箱子位置与推动方向。
- 状态 DFS / BFS 推箱子:以 “箱子所在格 + 当前推动方向” 为状态搜索。若箱子前后格均为空则可推动;同时对缩点图进行判定,看 Bessie 是否能绕到另一个方向继续推动。
最后在状态表中检查每个询问位置四个方向是否得到访问即可。
#include<bits/stdc++.h> #define ci const int using namespace std; ci N=1505*1505*1.5,M=1505,fx[4]={1,-1,0,0},fy[4]={0,0,1,-1}; int n,m,Q,id[M][M],ax,ay,bx,by,cnt,mp[M][M]; int dfn[N],low[N],st[N],top,dfstime,dep[N],D[N],tot,siz[N],son[N],tp[N],f[N],rt[N]; vector<int>g[N],G[N]; void Add(ci x,ci y){ G[x].push_back(y),G[y].push_back(x); } void tarjan(ci x){ st[++top]=x,dfn[x]=low[x]=++dfstime; for(int y:g[x]) if(!dfn[y]){ tarjan(y),low[x]=min(low[x],low[y]); if(low[y]==dfn[x]){ ++cnt; while(st[top]!=y)Add(st[top--],cnt); Add(st[top--],cnt); Add(x,cnt); } } else low[x]=min(low[x],dfn[y]); } void dfs(ci x){ dep[x]=dep[f[x]]+1,D[x]=++tot,siz[x]=1; if(!rt[x])rt[x]=x; for(int y:G[x]) if(y!=f[x]) f[y]=x,rt[y]=rt[x],dfs(y),siz[x]+=siz[y], son[x]=siz[y]>siz[son[x]]?y:son[x]; } void DFS(ci x){ if(!tp[x])tp[x]=x; if(son[x])tp[son[x]]=tp[x],DFS(son[x]); for(int y:G[x])if(!tp[y])DFS(y); } int in(ci x,ci y){ return D[x]<=D[y]&&D[y]<D[x]+siz[x]; } int lca(int x,int y){ int fx=tp[x],fy=tp[y]; while(fx!=fy){ if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy); x=f[fx],fx=tp[x]; } return dep[x]<dep[y]?x:y; } bool check(ci x,ci y,ci a){ if(rt[x]!=rt[y])return 1; ci l=lca(x,y); if(a==l)return 1; return (in(l,a)&&in(a,x))||(in(l,a)&&in(a,y)); } bool vis[M][M][4]; struct node{ int x,y,d; }; queue<node>q; void ins(ci x,ci y,ci d){ if(!vis[x][y][d])vis[x][y][d]=1,q.push({x,y,d}); } int main(){ scanf("%d%d%d",&n,&m,&Q); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ id[i][j]=++cnt; char c=getchar(); while(c!='.'&&c!='#'&&c!='A'&&c!='B')c=getchar(); if(c=='A')ax=i,ay=j; if(c=='B')bx=i,by=j; if(c=='#')mp[i][j]=1; } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(!mp[i][j]){ if(i!=n&&!mp[i+1][j])g[id[i][j]].push_back(id[i+1][j]),g[id[i+1][j]].push_back(id[i][j]); if(j!=m&&!mp[i][j+1])g[id[i][j]].push_back(id[i][j+1]),g[id[i][j+1]].push_back(id[i][j]); } for(int i=1;i<=n*m;++i) if(!dfn[i]) tarjan(i),dfs(i),DFS(i); for(int d=0;d<4;++d){ ci x=bx+fx[d],y=by+fy[d]; if(x<1||x>n||y<1||y>m||mp[x][y])continue; if(!check(id[ax][ay],id[x][y],id[bx][by]))ins(bx,by,d); } while(!q.empty()){ ci x=q.front().x,y=q.front().y,d=q.front().d;q.pop(); for(int d2=0;d2<4;++d2){ ci xx=x+fx[d2],yy=y+fy[d2]; if(d==d2||mp[xx][yy]||xx<1||xx>n||yy<1||yy>m)continue; if(!check(id[x+fx[d]][y+fy[d]],id[xx][yy],id[x][y]))ins(x,y,d2); } ci xx=x-fx[d],yy=y-fy[d]; if(xx<1||xx>n||yy<1||yy>m||mp[xx][yy])continue; ins(xx,yy,d); } for(int x,y;Q;--Q){ scanf("%d%d",&x,&y); if((x==bx&&y==by)||vis[x][y][0]||vis[x][y][1]||vis[x][y][2]||vis[x][y][3])puts("YES"); else puts("NO"); } return 0; }
- 1
信息
- ID
- 3251
- 时间
- 3000ms
- 内存
- 512MiB
- 难度
- 9
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者