USACO 2017 December Contest Platinum T2: Push a Box
Posted li-dox
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了USACO 2017 December Contest Platinum T2: Push a Box相关的知识,希望对你有一定的参考价值。
题目大意
一个谷仓是一个N*M的矩形网格,有一些网格里有干草。Bessie站在其中一个格子内,还有一个格子里有一个大木箱。Bessie不能和大木箱在一个格子里,也不能和干草在一个格子里。
如果她不与干草一个格子,她就可以往自己旁边的四个方向(东西南北)移动,如果她想移动到有木箱的格子里,那个木箱就会被她推一格(只要木箱的那个方向还有空间),如果没有空间,那Bessie就不能移动了。
给你谷仓的布局(空格子,干草以及木箱位置)以及Bessie的出发位置和箱子要被推到的位置,请你帮忙计算Bessie能不能把木箱推到指定位置。
题目分析
观察题目,发现并没有什么优秀的做法,所以只能考虑搜索。
然而单纯的搜索肯定是不行的,问题就是如何判断不经过箱子所在的点,从箱子的一个相邻点走到另一个相邻点。
也就是说,两个点就有两条点不相交的路径可以相互到达,这就等价于这两个点属于同一个点双连通分量。考虑使用圆方树判断一下。(一个点最多属于四个点双)
这样我们就可以顺利地bfs了。
更多细节看代码注释。
1 #include<bits/stdc++.h> 2 #define PII pair<int,int> 3 #define MK make_pair 4 #define fir first 5 #define sec second 6 7 using namespace std; 8 const int MAXN=1510; 9 10 struct Node 11 int px,py,bx,by; 12 ; 13 int n,m,q; 14 int px,py,bx,by; 15 int dx[5]=-1,0,1,0; 16 int dy[5]=0,-1,0,1; 17 int PDCC,InCpr[MAXN][MAXN][5];// 点双个数,属于某个点的点双元素 18 19 int tim,dfn[MAXN][MAXN],low[MAXN][MAXN]; 20 char g[MAXN][MAXN]; 21 stack<PII > stk; 22 23 bool Up,Dn,Lft,Rt,vis[MAXN][MAXN][5],B_vis[MAXN][MAXN]; 24 25 inline bool Inside(int x,int y) 26 return (x>=1&&x<=n&&y>=1&&y<=m); 27 28 inline void AddNear(int x,int y,int Id) 29 InCpr[x][y][++InCpr[x][y][0]]=Id; 30 31 inline void Tarjan(int x,int y,int fx,int fy) 32 dfn[x][y]=low[x][y]=++tim; 33 stk.push(MK(x,y)); 34 for(int i=0,xx,yy;i<4;++i) 35 xx=x+dx[i];yy=y+dy[i]; 36 if(Inside(xx,yy)&&g[xx][yy]!=‘#‘) 37 if(!dfn[xx][yy]) 38 Tarjan(xx,yy,x,y); 39 if(low[xx][yy]>=dfn[x][y]) 40 ++PDCC; 41 AddNear(x,y,PDCC); 42 while(stk.top().fir!=xx||stk.top().sec!=yy) 43 AddNear(stk.top().fir,stk.top().sec,PDCC); 44 stk.pop(); 45 46 AddNear(xx,yy,PDCC); 47 stk.pop(); 48 49 low[x][y]=min(low[x][y],low[xx][yy]); 50 51 else if(dfn[x][y]>dfn[xx][yy]&&(xx!=fx||yy!=fy)) 52 low[x][y]=min(low[x][y],dfn[xx][yy]); 53 54 55 56 inline void BeClose() //直接bfs就行 57 queue<PII > Q; 58 Q.push(MK(px,py)); 59 B_vis[px][py]=true; 60 while(!Q.empty()) 61 PII p=Q.front(); 62 Q.pop(); 63 if(p.fir==bx-1&&p.sec==by) Up=true; 64 if(p.fir==bx+1&&p.sec==by) Dn=true; 65 if(p.fir==bx&&p.sec==by-1) Lft=true; 66 if(p.fir==bx&&p.sec==by+1) Rt=true; 67 if(Up&&Dn&&Lft&&Rt) continue; 68 for(int i=0,xx,yy;i<4;++i) 69 xx=p.fir+dx[i]; 70 yy=p.sec+dy[i]; 71 if(Inside(xx,yy)&&g[xx][yy]!=‘#‘&&g[xx][yy]!=‘B‘&&!B_vis[xx][yy]) 72 B_vis[xx][yy]=true; 73 Q.push(MK(xx,yy)); 74 75 76 77 78 inline bool InSameCpr(int s,int t,int p,int q) //判断在一个点双内 79 for(int i=1;i<=InCpr[s][t][0];++i) 80 for(int j=1;j<=InCpr[p][q][0];++j) 81 if(InCpr[s][t][i]==InCpr[p][q][j]) 82 return true; 83 return false; 84 85 inline void Bfs() 86 queue<Node> Q; 87 if (Up) Q.push(Nodebx-1,by,bx,by),vis[bx][by][0]=true; 88 if (Lft)Q.push(Nodebx,by-1,bx,by),vis[bx][by][1]=true; 89 if (Dn) Q.push(Nodebx+1,by,bx,by),vis[bx][by][2]=true; 90 if (Rt) Q.push(Nodebx,by+1,bx,by),vis[bx][by][3]=true; 91 while(!Q.empty()) 92 Node p=Q.front();Q.pop(); 93 for(int i=0;i<4;++i) 94 int nbx=p.bx+dx[i],nby=p.by+dy[i]; 95 int bkx=p.bx+dx[i^2],bky=p.by+dy[i^2]; 96 if(Inside(nbx,nby)&&g[nbx][nby]!=‘#‘&&((bkx==p.px&&bky==p.py)||InSameCpr(p.px,p.py,bkx,bky))&&!vis[nbx][nby][i^2]) 97 vis[nbx][nby][i^2]=1; 98 Q.push(Nodep.bx,p.by,nbx,nby); 99 100 101 102 103 int main() 104 scanf("%d%d%d",&n,&m,&q); 105 for(int i=1;i<=n;++i) 106 for(int j=1;j<=m;++j) 107 char ch=getchar(); 108 if(ch^‘.‘&&ch^‘#‘&&ch^‘A‘&&ch^‘B‘) //如果不是合法字符 109 --j;continue; 110 111 if(ch==‘A‘) px=i,py=j; 112 if(ch==‘B‘) bx=i,by=j; 113 g[i][j]=ch; 114 115 // cout<<1<<endl; 116 Tarjan(px,py,0,0); //看看人所在点可以到达哪些点,并建出点双连通分量 117 // cout<<1<<endl; 118 if(!dfn[bx][by]) //如果一开始就到不了bx,by 119 while(q--) 120 int x,y; 121 scanf("%d%d",&x,&y); 122 puts(x==bx&&y==by?"YES":"NO"); 123 124 return 0; 125 126 BeClose(); //先让人接近箱子,看看能到箱子的哪些邻近位置,方便bfs 127 Bfs(); 128 while(q--) 129 int x,y; 130 scanf("%d%d",&x,&y); 131 puts(vis[x][y][0]||vis[x][y][1]||vis[x][y][2]||vis[x][y][3]?"YES":"NO"); 132 133 return 0; 134
以上是关于USACO 2017 December Contest Platinum T2: Push a Box的主要内容,如果未能解决你的问题,请参考以下文章
USACO 2017 December Contest Platinum T2: Push a Box
USACO 2017 December Contest Platinum T3: Greedy Gift Takers
USACO 2017 December Contest Gold T1: A Pie for a Pie
USACO 2016 December Contest Gold T1: Moocast
USACO 2007 December Contest, Silver Problem 2. Building Roads Kruskal最小生成树算法