zoukankan      html  css  js  c++  java
  • 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(Node{bx-1,by,bx,by}),vis[bx][by][0]=true; 
     88     if (Lft)Q.push(Node{bx,by-1,bx,by}),vis[bx][by][1]=true;
     89     if (Dn) Q.push(Node{bx+1,by,bx,by}),vis[bx][by][2]=true;
     90     if (Rt) Q.push(Node{bx,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(Node{p.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 }
  • 相关阅读:
    IDEA的JDBC报错解决
    java注解
    Java反射
    javaIO
    工程师的认知
    前端的一些性能提升
    ES6函数的扩展
    2020新年愿望
    高维护性的javascript
    Chrome Dev tools的几点小技巧
  • 原文地址:https://www.cnblogs.com/LI-dox/p/11235588.html
Copyright © 2011-2022 走看看