(貌似有圆方树的做法,我写的是点双)

显然这道题就是直接搜索。定义状态为f[i][j][0~4]表示箱子在(i,j),人在某个方向推。然后问题就是怎么转向。我们发现如果要转向,必须是人走过一条不包括(i,j)的路径到另一个方向。那么直接求一个点双联通分量就完事了。把点双联通里面的点两两之间都有至少两条不经过重复点的路径,这样就能转向了。

点双内,具体的处理方法是开一个桶。

具体见代码

CODE

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1505;
const int MAXP = MAXN*MAXN;
int n, m, q, id[MAXN][MAXN], tot, tmr;
int fir[MAXP], to[MAXP<<2], nxt[MAXP<<2], cnt, A, B;
int dfn[MAXP], low[MAXP], stk[MAXP], indx, scc[MAXP];
char s[MAXN][MAXN];
pair<int,int>pos[MAXP]; inline void link(int u, int v) {
to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt;
to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt;
}
bool vis[MAXN][MAXN];
bool can[MAXN][MAXN][4][4];
//0 : L
//1 : R
//2 : U
//3 : D
const int Dx[4] = { 0, 0, -1, 1 };
const int Dy[4] = { -1, 1, 0, 0 };
inline void ins(int k) {
vis[pos[k].first][pos[k].second] = 1;
for(int u, v, i = 0; i < 4; ++i) {
u = pos[k].first - Dx[i];
v = pos[k].second - Dy[i];
if(u >= 1 && u <= n && v >= 1 && v <= m && s[u][v] != '#') {
for(int x, y, j = 0; j < 4; ++j) if(j!=i) { //可能x,y被重复枚举到,但是没关系,常数问题
x = u + Dx[j], y = v + Dy[j];
if(x >= 1 && x <= n && y >= 1 && y <= m && s[x][y] != '#' && vis[x][y])
can[u][v][i][j] = can[u][v][j][i] = 1;
}
}
}
}
inline void del(int k) {
vis[pos[k].first][pos[k].second] = 0;
}
inline void tarjan(int u, int ff) {
dfn[u] = low[u] = ++tmr;
stk[++indx] = u;
for(int v, i = fir[u], j; i; i = nxt[i])
if((v=to[i]) != ff) {
if(!dfn[v]) {
tarjan(v, u), low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]) {
for(j = indx; ; --j) {ins(stk[j]); if(stk[j] == v) break; } ins(u);
for(j = indx; ; --j) {del(stk[j]); if(stk[j] == v) break; } del(u);
indx = j-1;
}
}
else low[u] = min(low[u], dfn[v]);
}
} bool dis[MAXN][MAXN];
inline void bfs(int Sx, int Sy) {
queue<pair<int,int> >Q;
Q.push(pair<int, int>(Sx, Sy));
dis[Sx][Sy] = 1;
while(!Q.empty()) {
int u = Q.front().first, v = Q.front().second; Q.pop();
for(int x, y, i = 0; i < 4; ++i) {
x = u + Dx[i], y = v + Dy[i];
if(x >= 1 && x <= n && y >= 1 && y <= m && s[x][y] == '.' && !dis[x][y]) {
dis[x][y] = 1, Q.push(pair<int, int>(x, y));
}
}
}
}
struct node {
int x, y, z;
node(){}
node(int x, int y, int z):x(x), y(y), z(z){}
};
bool f[MAXN][MAXN][4];
queue<node>que;
int main () {
freopen("pushbox.in", "r", stdin);
freopen("pushbox.out", "w", stdout);
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= n; ++i) {
scanf("%s", s[i]+1);
for(int j = 1; j <= m; ++j) {
if(s[i][j] != '#') {
id[i][j] = ++tot;
pos[tot] = pair<int,int>(i, j);
if(j > 1 && s[i][j-1] != '#') link(id[i][j-1], id[i][j]);
if(i > 1 && s[i-1][j] != '#') link(id[i-1][j], id[i][j]);
}
if(s[i][j] == 'A') A = id[i][j];
if(s[i][j] == 'B') B = id[i][j];
}
}
tarjan(B, 0);
bfs(pos[A].first, pos[A].second);
int Sx = pos[B].first, Sy = pos[B].second;
if(dis[Sx][Sy-1]) f[Sx][Sy][0] = 1, que.push(node(Sx, Sy, 0));
if(dis[Sx][Sy+1]) f[Sx][Sy][1] = 1, que.push(node(Sx, Sy, 1));
if(dis[Sx-1][Sy]) f[Sx][Sy][2] = 1, que.push(node(Sx, Sy, 2));
if(dis[Sx+1][Sy]) f[Sx][Sy][3] = 1, que.push(node(Sx, Sy, 3));
while(!que.empty()) {
int u = que.front().x, v = que.front().y, w = que.front().z; que.pop();
int x = u - Dx[w], y = v - Dy[w];
if(x >= 1 && x <= n && y >= 1 && y <= m && s[x][y] != '#' && !f[x][y][w])
f[x][y][w] = 1, que.push(node(x, y, w));
for(int i = 0; i < 4; ++i)
if(i != w && can[u][v][w][i] && !f[u][v][i]) {
f[u][v][i] = 1, que.push(node(u, v, i));
}
}
int Tx, Ty;
while(q--) {
scanf("%d%d", &Tx, &Ty);
puts((s[Tx][Ty] == 'B' || f[Tx][Ty][0] || f[Tx][Ty][1] || f[Tx][Ty][2] || f[Tx][Ty][3]) ? "YES" : "NO");
}
}

md变量写错调我2h。

Luogu P4082 [USACO17DEC]Push a Box 点双连通分量/圆方树的更多相关文章

  1. luogu P4082 [USACO17DEC]Push a Box

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

  2. BZOJ 压力 tarjan 点双联通分量+树上差分+圆方树

    题意 如今,路由器和交换机构建起了互联网的骨架.处在互联网的骨干位置的核心路由器典型的要处理100Gbit/s的网络流量. 他们每天都生活在巨大的压力之下.小强建立了一个模型.这世界上有N个网络设备, ...

  3. HDU 4612 Warm up (边双连通分量+缩点+树的直径)

    <题目链接> 题目大意:给出一个连通图,问你在这个连通图上加一条边,使该连通图的桥的数量最小,输出最少的桥的数量. 解题分析: 首先,通过Tarjan缩点,将该图缩成一颗树,树上的每个节点 ...

  4. Gym - 100676H H. Capital City (边双连通分量缩点+树的直径)

    https://vjudge.net/problem/Gym-100676H 题意: 给出一个n个城市,城市之间有距离为w的边,现在要选一个中心城市,使得该城市到其余城市的最大距离最短.如果有一些城市 ...

  5. [USACO17DEC]Push a Box

    https://www.zybuluo.com/ysner/note/1293166 题面 戳我 解析 挺不错的一道图论码量题. 可以借此回顾一下\(noip2013\)华容道. 思路和华容道差不多. ...

  6. Luogu P4606 [SDOI2018] 战略游戏 圆方树 虚树

    https://www.luogu.org/problemnew/show/P4606 把原来的图的点双联通分量缩点(每个双联通分量建一个点,每个割点再建一个点)(用符合逻辑的方式)建一棵树(我最开始 ...

  7. hdu4612 Warm up[边双连通分量缩点+树的直径]

    给你一个连通图,你可以任意加一条边,最小化桥的数目. 添加一条边,发现在边双内是不会减少桥的.只有在边双与边双之间加边才有效.于是,跑一遍边双并缩点,然后就变成一棵树,这样要加一条非树边,路径上的点( ...

  8. UOJ#23. 【UR #1】跳蚤国王下江南 仙人掌 Tarjan 点双 圆方树 点分治 多项式 FFT

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ23.html 题目传送门 - UOJ#23 题意 给定一个有 n 个节点的仙人掌(可能有重边). 对于所有 ...

  9. UOJ#30/Codeforces 487E Tourists 点双连通分量,Tarjan,圆方树,树链剖分,线段树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ30.html 题目传送门 - UOJ#30 题意 uoj写的很简洁.清晰,这里就不抄一遍了. 题解 首先建 ...

随机推荐

  1. 【数据结构 Python & C++】顺序表

    用C++ 和 Python实现顺序表的简单操作 C++代码 // Date:2019.7.31 // Author:Yushow Jue #include<iostream> using ...

  2. 加密算法 MD5 和 SHA 的 JAVA 实现

    首先先简单的介绍一下MD5 和 SHA 算法 然后看一下在  java.security.MessageDigest   (信息摘要包下) 如何分别实现  md5 加密 和 sha 加密 最后在看一下 ...

  3. C# Unix时间戳和DateTime类型相互转换

    /// <summary> /// 将Unix时间戳转换为DateTime类型时间 /// </summary> /// <param name="d" ...

  4. Asp.Net Core 轻松学系列-3项目目录和文件作用介绍

    目录 前言 结语 前言     上一章介绍了 Asp.Net Core 的前世今生,并创建了一个控制台项目编译并运行成功,本章的内容介绍 .NETCore 的各种常用命令.Asp.Net Core M ...

  5. python - pyxel 制作游戏

    之前看了一个项目,觉得还挺有意思的,是关于做一个像素风的游戏,现在,虚幻4,u3d,已经让游戏愈发的好看,好玩,曾经我们童年的像素风游戏,愈来愈少.所以,这里我们就回味下. Pyxel是一个pytho ...

  6. 关于一个mvc架构的cms的后台getshell

    都知道,mvc的话 除了根目录还有public目录可以访问,其他的访问都是不行的,因为会默认都是会解析url 然后我们来看今天的猪脚 大概的图片上传还有远程文件加载我黑盒测过了  就是想捞一个快一点的 ...

  7. leetcode-104.二叉树最大深度 · BTree + 递归

    easy 题就不详细叙述题面和样例了,见谅. 题面 统计二叉树的最大深度. 算法 递归搜索二叉树,返回左右子树的最大深度. 源码 class Solution { public: int maxDep ...

  8. java序列化和反序列化使用总结

    一.概念 java对象序列化的意思就是将对象的状态转化成字节流,以后可以通过这些值再生成相同状态的对象.对象序列化是对象持久化的一种实现方法,它是将对象的属性和方法转化为一种序列化的形式用于存储和传输 ...

  9. 阿里P7分享如何面对枯燥的源码

    一个软件开发人员,工作到了一定的年限(一般是3.4年左右),如果他还没学会阅读源码,那么他就会遇到瓶颈.因为到了这个时候的开发,他应该不仅仅只会做那些 CURD 的业务逻辑,而应该会根据公司的实际情况 ...

  10. ajax _flask

    同步访问 当客户端向服务器发送请求时,服务器在处理过程中,浏览器只能等等,效率偏低 异步访问: 当客户端向服务器发送请求时,服务器在处理过程中,客户端可以做其他的操作,不需要一直等待,效率偏高 AJA ...