标签:方法 style problem clu 方向 nbsp == continue org
题面
https://www.luogu.org/problem/P4082
题解
一道梵高级别的水题。但是因为是自己想出来的比较自豪,所以就写了。
$F[x][y][s]$代表石头在$(x,y)$,人在$(x+dx[s],y+dy[s])$,转移有两种,一种是推一步,一种是换个方向。
要判断“换个方向”时,是否可以走到那里,所以把点双求出来,把石头就看做割点,这里不需要建圆方树判断,因为如果它们不在一个点双里,说明只有唯一一条路(走石头),并且被堵上了,所以不能走过去,如果它们在一个点双里,说明可以到达。
判断两点是不是在一个点双里,我想了一下,发现没有特别好的方法,题解也写的暴力,那就暴力吧。
#include<stack> #include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ri register int #define N 1550 using namespace std; int n,m,q,vis[N][N],vis2[N][N][4],id[N][N]; int dfn[N*N],low[N*N],cnt,bccnt; vector<int> bel[N*N]; char g[N][N]; stack<int> s; const int dx[]={1,-1,0,0}; const int dy[]={0,0,1,-1}; struct graph { vector<int> to[N*N]; void add_edge(int u,int v) {to[u].push_back(v);} void tarjan(int x) { dfn[x]=low[x]=++cnt; s.push(x); for (ri i=0;i<to[x].size();i++) { int y=to[x][i]; if (dfn[y]) { low[x]=min(low[x],dfn[y]); } else { tarjan(y); low[x]=min(low[x],low[y]); if (low[y]>=dfn[x]) { ++bccnt; while (1) { int t=s.top(); s.pop(); bel[t].push_back(bccnt); if (t==y) break; } bel[x].push_back(bccnt); } } } } } G; struct node{int x,y;}; struct node2{int x,y,s;}; bool check(int ax,int ay,int bx,int by) { int a=id[ax][ay],b=id[bx][by]; for (ri i=0;i<bel[a].size();i++) for (ri j=0;j<bel[b].size();j++) if (bel[a][i]==bel[b][j]) return 1; return 0; } void bfs2(int sx,int sy,int opt) { queue<node2> q; q.push((node2){sx,sy,opt}); vis2[sx][sy][opt]=1; while (!q.empty()) { int x=q.front().x,y=q.front().y,s=q.front().s; q.pop(); for (ri i=0;i<4;i++) { if (i==s) continue; int nx=x+dx[i],ny=y+dy[i]; if (!id[nx][ny] || vis2[x][y][i]) continue; if (check(nx,ny,x+dx[s],y+dy[s])) vis2[x][y][i]=1,q.push((node2){x,y,i}); } int nx=x+dx[s^1],ny=y+dy[s^1]; if (!id[nx][ny] || vis2[nx][ny][s]) continue; vis2[nx][ny][s]=1,q.push((node2){nx,ny,s}); } } void bfs(int ax,int ay,int bx,int by) { queue<node> q; q.push((node){ax,ay}); vis[ax][ay]=1; while (!q.empty()) { int x=q.front().x,y=q.front().y; q.pop(); for (ri i=0;i<4;i++) { int nx=x+dx[i],ny=y+dy[i]; if (vis[nx][ny] || !id[nx][ny]) continue; vis[nx][ny]=1; q.push((node){nx,ny}); if (nx==bx && ny==by) { bfs2(bx,by,i^1); return; } } } } int main(){ scanf("%d %d %d",&n,&m,&q); memset(g,‘#‘,sizeof(g)); for (ri i=1;i<=n;i++) scanf("%s",g[i]+1),g[i][m+1]=‘#‘; int cc=0; for (ri i=1;i<=n;i++) for (ri j=1;j<=m;j++) if (g[i][j]!=‘#‘) id[i][j]=++cc; for (ri i=1;i<=n;i++) for (ri j=1;j<=m;j++) if (id[i][j]) { for (ri k=0;k<4;k++) { int nx=i+dx[k],ny=j+dy[k]; if (id[nx][ny]) G.add_edge(id[i][j],id[nx][ny]); } } for (ri i=1;i<=n;i++) for (ri j=1;j<=m;j++) if (id[i][j] && !dfn[id[i][j]]) G.tarjan(id[i][j]); int ax,ay,bx,by; for (ri i=1;i<=n;i++) for (ri j=1;j<=m;j++) if (g[i][j]==‘A‘) ax=i,ay=j; for (ri i=1;i<=n;i++) for (ri j=1;j<=m;j++) if (g[i][j]==‘B‘) bx=i,by=j; bfs(ax,ay,bx,by); int a,b; for (ri i=1;i<=q;i++) { scanf("%d %d",&a,&b); bool ans=(a==bx && b==by); for (ri j=0;j<4;j++) ans|=vis2[a][b][j]; if (ans) puts("YES"); else puts("NO"); } return 0; }
标签:方法 style problem clu 方向 nbsp == continue org
原文地址:https://www.cnblogs.com/shxnb666/p/11420651.html