https://www.zybuluo.com/ysner/note/1293166

题面

戳我

解析

挺不错的一道图论码量题。

可以借此回顾一下\(noip2013\)华容道。

思路和华容道差不多。

照洛谷数据规模看,暴搜可能有\(\frac{1}{3}\)的分数。。。

设\(f[w][i][j]\)表示箱子在点\((i,j)\)时,人能否到达\(w\)方向(即\(0/1/2/3\),表示上下左右)。

那么我们可以先从人出发\(BFS\)一遍,预处理出未推箱子时的\(f[w][i][j]\)。

注意箱子所在点是可以多次更新的。

然后开始推箱子,每次有两种决策:

  • 换个方向
  • 照原方向推一格

决策可不可行肯定要预处理出来,毕竟\(n\)是\(10^6\)级别的。

显然如果能换方向,就说明换方向的前后两点在同一点双联通分量中。

这玩意儿从人的出发点跑一遍\(Tarjan\)就能预处理出来。

推一格这个操作可以直接转移。

注意边界都要赋为\(\#\)。(尤其是每行末尾)

细节挺多,蒟蒻调了两个多小时。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#define ll long long
#define re register
#define il inline
#define pb(a) push_back(a)
#define gc() getchar()
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=1644;
int n,m,q,sx,sy,rx,ry,dfn[N*N],low[N*N],top,sta[N*N],tot,Id[N][N];
int mx[4]={1,-1,0,0},my[4]={0,0,1,-1};
bool f[4][N][N],vis[N][N];
char mp[N][N];
struct dat{int x,y,w;};
queue<dat>Q;
vector<int>c[N*N];
il int id(re int x,re int y){return Id[x][y];}
il int gi()
{
re int x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=gc();
if(ch=='-') t=-1,ch=gc();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=gc();
return x*t;
}
il void Tarjan(re int x,re int y,re int fx,re int fy)
{
re int u=id(x,y);
sta[++top]=u,dfn[u]=low[u]=++tot;
fp(i,0,3)
{
re int xx=x+mx[i],yy=y+my[i],v=id(xx,yy);
if(mp[xx][yy]=='#') continue;
if(xx==fx&&yy==fy) continue;
if(!dfn[v])
{
Tarjan(xx,yy,x,y);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u])
{
++tot;re int g;
do{g=sta[top--];c[g].pb(tot);}while(g^v);
c[u].pb(tot);
}
}
else low[u]=min(low[u],dfn[v]);
}
}
il void BFS1()
{
Q.push((dat){rx,ry,0});vis[rx][ry]=1;
while(!Q.empty())
{
re int x=Q.front().x,y=Q.front().y,u=id(x,y);Q.pop();
fp(i,0,3)
{
re int xx=x+mx[i],yy=y+my[i],v=id(xx,yy);
if(mp[xx][yy]=='#'||vis[xx][yy]) continue;
if(xx==sx&&yy==sy) {f[i^1][xx][yy]=1;continue;}
vis[xx][yy]=1;Q.push((dat){xx,yy,0});
}
}
}
il int check(re int x,re int y,re int xx,re int yy)
{
re int u=id(x,y),v=id(xx,yy);
for(re int i=0;i<c[u].size();++i)
for(re int j=0;j<c[v].size();++j)
if(c[u][i]==c[v][j]) return 1;
return 0;
}
il void BFS2()
{
fp(i,0,3) if(f[i][sx][sy]) Q.push((dat){sx,sy,i});
while(!Q.empty())
{
re int x=Q.front().x,y=Q.front().y,w=Q.front().w,u=id(x,y);Q.pop();
fp(i,0,3)
{
if(f[i][x][y]) continue;
re int xx=x+mx[i],yy=y+my[i];
if(mp[xx][yy]=='#') continue;
if(check(x+mx[w],y+my[w],xx,yy)) f[i][x][y]=1,Q.push((dat){x,y,i});
}
{
re int xx=x+mx[w^1],yy=y+my[w^1];///yy=y+mx???????
if(mp[xx][yy]=='#') continue;
if(!f[w][xx][yy]) f[w][xx][yy]=1,Q.push((dat){xx,yy,w});
}
}
}
int main()
{
n=gi();m=gi();q=gi();
memset(mp,'#',sizeof(mp));
fp(i,1,n) scanf("%s",mp[i]+1),mp[i][m+1]='#';
fp(i,1,n)
fp(j,1,m)
{
if(mp[i][j]=='A') rx=i,ry=j,mp[i][j]='.';
else if(mp[i][j]=='B') sx=i,sy=j,mp[i][j]='.';
Id[i][j]=(i-1)*m+j;
}
Tarjan(rx,ry,0,0);
BFS1();
BFS2();
while(q--)
{
re int x=gi(),y=gi(),tag=(sx==x&&sy==y);
fp(i,0,3) tag|=f[i][x][y];
puts(tag?"YES":"NO");
}
return 0;
}

[USACO17DEC]Push a Box的更多相关文章

  1. luogu P4082 [USACO17DEC]Push a Box

    传送门 一个人推箱子,和之前的华容道中的棋子移动有异曲同工之妙,因为每次可以让人走到箱子的其他方向上,或者推一下箱子 所以状态可以设成\(f_{i,j,k}\),即箱子在\((i,j)\),人在\(k ...

  2. Luogu P4082 [USACO17DEC]Push a Box 点双连通分量/圆方树

    (貌似有圆方树的做法,我写的是点双) 显然这道题就是直接搜索.定义状态为f[i][j][0~4]表示箱子在(i,j),人在某个方向推.然后问题就是怎么转向.我们发现如果要转向,必须是人走过一条不包括( ...

  3. 【BZOJ5138】[Usaco2017 Dec]Push a Box(强连通分量)

    [BZOJ5138][Usaco2017 Dec]Push a Box(强连通分量) 题面 BZOJ 洛谷 题解 这题是今天看到萝卜在做然后他一眼秒了,我太菜了不会做,所以就来做做. 首先看完题目,是 ...

  4. bzoj5138 [Usaco2017 Dec]Push a Box

    题目描述: bz luogu 题解: 暴力可以记录$AB$位置转移,这个时候状态是$n^4$的,无法接受. 考虑只记录$A$在$B$旁边时的状态,这个时候状态时$n^2$的. 所以说转移有两种,一种是 ...

  5. FlasActionScript3随学随机

    1.跳转页面代码.下载代码(new URLRequest(下载地址)): var request1:URLRequest=new URLRequest("http://www.baidu.c ...

  6. [游戏模版17] Win32 推箱子 迷宫

    >_<:Here introduce a simple game: >_<:resource >_<:only can push a box and finally ...

  7. POJ-1475-Pushing Boxes(BFS)

    Description Imagine you are standing inside a two-dimensional maze composed of square cells which ma ...

  8. js的基本的一些方法

    我们不是要背诵东西,只是因为这是我们生存的技能. 加油吧少年! 1.函数的块级作用域和函数的自我执行是一回事.!(function () { function box(){alert('hello') ...

  9. poj 1475 || zoj 249 Pushing Boxes

    http://poj.org/problem?id=1475 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=249 Pushin ...

随机推荐

  1. db2事务日志已满解决办法

    查看事务日志配置(MICRO_11为数据库名称): db2 get db cfg for MICRO_11 运行结果: 日志文件大小(4KB)                         (LOG ...

  2. Matplotlib中的颜色

    使用matplotlib中会遇到选择颜色的问题,很多人会觉得自带的matlab风格的颜色不好看.好在Matplotlib已经预见到了这个问题,除了支持最基本的matlab传统颜色之外,还支持很多种颜色 ...

  3. N分之一 竖式除法模拟

    N分之一 Description Alice越来越痴迷于数学问题了.一天,爸爸出了个数学题想难倒她,让她求1 / n. 可怜的Alice只有一岁零九个月,回答不上来 ~~~~(>_<)~~ ...

  4. Springboot+dubbo+zookeeper整合

    本想自己搭建一个Spring+dubbo+zookeeper整合好的框架,想寻找个最佳实现但是遇到各种各样的问题,只好自己看看dubbo starter的源码 整理如下: 通过打上断点来看配置的对不对 ...

  5. HDU3032 nim博弈

    题目大意: 可以从某一堆中取任意个数,也可把一堆分成两个不为0的堆,直到某一方无法操作为输 因为是nim博弈,所以只要考虑一堆时候的sg值,把所有堆的sg值异或即可 很显然这里 0 是一个终止态 sg ...

  6. 舒适的路线(codevs 1001)

    题目描述 Description Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光.Z小镇附近共有N(1<N≤500)个景点(编号为1,2,3,…,N),这些景点被M(0<M≤ ...

  7. [bzoj1578][Usaco2009 Feb]Stock Market 股票市场_完全背包dp

    Stock Market 股票市场 bzoj-1578 Usaco-2009 Feb 题目大意:给定一个$S\times D$的大矩阵$T$,其中$T[i][j]$表示第i支股票第j天的价格.给定初始 ...

  8. Windows 10+Ubuntu 16.04在MBR分区上安装双系统之后没有Windows 10的启动菜单解决方法

    背景: 硬盘分区方式:MBR 硬盘容量256,Windows 100,Ubuntu 156,其中主分区安装的是Windows,Ubuntu安装在逻辑分区上,文件系统为Ext4,整个Ubuntu就挂载在 ...

  9. Redis集群方案收集

    说明: 如果不考虑客户端分片去实现集群,那么市面上基本可以说就三种方案最成熟,它们分别如下所示: 系统 贡献者 是否官方Redis实现 编程语言 Twemproxy Twitter 是 C Redis ...

  10. Servlet实现页面重定向

    以下内容引用自http://wiki.jikexueyuan.com/project/servlet/page-redirect.html: 当文档移动到一个新的位置时,通常会使用页面重定向,需要将客 ...