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 }

原文地址:https://www.cnblogs.com/LI-dox/p/11235588.html

时间: 2024-10-11 20:59:07

USACO 2017 December Contest Platinum T2: Push a Box的相关文章

USACO 2018 December Contest Platinum T2: Sort It Out

题目大意 FJ有 N(1≤N≤1e5 )头奶牛(分别用 1…N 编号)排成一行.FJ喜欢他的奶牛以升序排列,不幸的是现在她们的顺序被打乱了.在过去FJ曾经使用一些诸如“冒泡排序”的开创性的算法来使他的奶牛排好序,但今天他想偷个懒.取而代之,他会每次对着一头奶牛叫道“按顺序排好”.当一头奶牛被叫到的时候,她会确保自己在队伍中的顺序是正确的(从她的角度看来).当有一头紧接在她右边的奶牛的编号比她小,她们就交换位置.然后,当有一头紧接在她左边的奶牛的编号比她大,她们就交换位置.这样这头奶牛就完成了“按

USACO 2017 December Contest Platinum T3: Greedy Gift Takers

题目大意 有 N(1≤N≤1e5)头牛按顺序排成一列,编号从 1 到 N,1 号牛在队头,N 号牛在队尾. 每次位于队头的牛 i 拿到一个礼物,然后插入到从队尾数ci?头牛之前的位置..举个栗子: 初始队列 1,2,3,4,5 c1?= 2,c2? = 3,则第一次操作后的序列为 2,3,1,4,5,第二次操作后的序列为 3,2,1,4,5.重复无限次操作,求最后有几头牛拿不到礼物. 题目分析 一上来有个显然的结论,若一个人得不到礼物那么原序列中在他后面的人肯定也得不到礼物,因为后面的人跳不到前

USACO 2017 December Contest Gold T1: A Pie for a Pie

题目大意 Bessie和Elsie各自烤了 N(1≤N≤10^5)个馅饼.Bessie 会这 2N 个馅饼打分,Elsie 也会.二者的打分均为一个 ≤1e9 的非负整数.由于她们口味不同,每个派的两个分数可能不同.她们想互赠礼物.开始时,Bessie 送给 Elsie 一个馅饼.她们收到礼物(对方做的馅饼)后都会回赠对方一个自己做的馅饼.她们选择回礼的方法相同.以 Elsie 为例,Elsie 根据自己的打分来选择回礼.回礼的分数至少要大于她收到的馅饼的分数,但两个馅饼的分数差不能大于 D(0

USACO 2007 December Contest, Silver Problem 2. Building Roads Kruskal最小生成树算法

PROBLEM: (ENGLISH VERSION) Farmer John had just acquired several new farms! He wants to connect the farms with roads so that he can travel from any farm to any other farm via a sequence of roads; roads already connect some of the farms. Each of the N

USACO 2015 February Contest Gold T2: Censoring

题目大意 FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10^5的字符串S.他有一个包含n个单词的列表,列表里的n个单词记为t1...tN.他希望从S中删除这些单词. FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词.他重复这个操作直到S中没有列表里的单词为止.注意删除一个单词后可能会导致S中出现另一个列表中的单词 FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是互不相同的

USACO 2016 December Contest Gold T3: Lasers and Mirrors

题目大意 出于某种原因,农夫约翰的牛总是在举行激光表演. 对于他们的最新展会,奶牛已经购买了一个大功率的激光器 - 这么大,事实上,他们似乎不能轻易地从它交付的位置移动.他们想以某种方式将激光的光发送到FJ物业另一侧的谷仓.激光器和谷仓都可以被认为位于FJ农场的地图上的2D平面中的点上.牛计划指挥激光器,使得它发出水平或竖直(即,与x或y轴平行)的光束.他们会将这个光束从一些镜子反射回去,直接到谷仓. 在农场上有N个栅栏(1≤N≤100,000),位于不同的二维点(也不同于激光和谷仓),牛可以安

USACO 2016 December Contest Gold T1: Moocast

题目大意 FJ的N头牛(1≤N≤1000)为了在他们之间传播信息, 想要组织一个"哞哞广播"系统. 奶牛们决定去用步话机装备自己而不是在很远的距离之外互相哞哞叫, 所以每一头奶牛都必须有一个步话机. 这些步话机都有一个限制传播半径, 但是奶牛们可以间接地通过中间奶牛传播信息, 所以并不是每头牛都必须直接向其他每一头奶牛连边. 奶牛们需要去决定多少钱花在步话机上, 如果他们花了$X, 那么他们都将会得到sqrt(x)距离的步话机. 所以, 两头牛之间的欧几里得距离平方最多是X. 请帮助奶

USACO 2019 January Contest Platinum T3: Train Tracking 2

题目大意 每天特快列车都会经过农场.列车有N节车厢(1≤N≤10^5),每节车厢上有一个1到10^9之间的正整数编号:不同的车厢可能会有相同的编号. 平时,Bessie会观察驶过的列车,记录车厢的编号.但是今天雾实在太浓了,Bessie一个编号也看不见!幸运的是,她从城市里某个可靠的信息源获知了列车编号序列的所有滑动窗口中的最小值.具体地说,她得到了一个正整数K,以及N−K+1个正整数c1,…,cN+1−K,其中ci是车厢i,i+1,…,i+K−1之中编号的最小值. 帮助Bessie求出满足所有

USACO 2019 February Contest Platinum T1: Cow Dating

题目大意 由于目前可供奶牛们使用的约会网站并没有给Farmer John留下深刻印象,他决定推出一个基于新匹配算法的奶牛交友网站,该算法可基于公牛和母牛间的共同兴趣对公牛和母牛进行匹配. Bessie在寻找情人节Barn Dance的合作伙伴时,决定试用这个网站.在注册账户之后,FJ的算法为他给出了一个长度为 N(1≤N≤1e6) 的匹配列表,列表上每头公牛接受她舞蹈邀请的概率为 p (0 < p < 1). Bessie决定向列表中的一个连续区间内的奶牛发送邀请,但Bessie希望恰好只有一