<更新提示>

<第一次更新>


<正文>

Pushbox

Description

周婧涵和她的小伙伴们发明了一个新游戏。游戏名字很准确,但不是特别有 创意。她们称之为“推动箱子在谷仓周围找到正确的位置,不要移动干草”游戏 (如果你认为这是浮夸的,你应该看到一些奶牛在编写代码时所使用的变量名 称…???)。

谷仓可以建模为一个 N×M 的矩形网格。一些网格单元中有干草。周婧涵在 这个网格中占据一个单元格,一个大木箱占据另一个单元格。周婧涵和木箱不能 同时放在同一个单元格中,也不能放入含有干草的单元格。

只要不走干草在的单元格,周婧涵可以在四个正交方向(北,东,南,西) 移动。如果她试图走到箱子所在的单元格,那么只要箱子的另一边有一个空的单 元格,箱子就会朝这个方向推动一个空间。如果没有空单元格,周婧涵将无法移 动。

一个特定的网格单元被指定为目标。周婧涵的目标是把箱子放到那个位置。

考虑到谷仓的布局、箱子和周婧涵的起始位置,以及箱子的目标位置,确定 是否有可能赢得比赛。

Input Format

第一行输入三个数字 N、M、Q,N 是网格的行数,M 是网格的列数。

1<=N,M<=1500 1<=Q<=50,000

接下来 N 行代表网格,内容由字符表示:空单元格(.),干草(#),周婧涵的起始位置(A)和木箱的初始位置(B)。

接下来是 Q 行,每行有一对整数(R,C)。 对于每一对,应该确定从谷仓 的初始状态开始是否有可能获得木箱的行 R,列 C。 起始行为 1,左起始列也是 1。

Output Format

Q 行,每行输出“YES”或者“NO”。

Sample Input

5 5 4
##.##
##.##
A.B..
##.##
##.##
3 2
3 5
1 3
5 3

Sample Output

NO
YES
NO
NO

解析

首先是\(bfs\)套\(bfs\)的暴力,第一重\(bfs\)箱子,第二重\(bfs\)人,时间复杂度\(O(n^2m^2)\),可以拿\(18\)分。

考虑优化,我们发现这道题只要判定合法性,于是第二重\(bfs\)肯定是我们优化的对象。

在暴力中,第二重\(bfs\)是用来找是否存在一条路径可以让人从箱子的一端不经过箱子走到另一端,这等价于判定箱子周围的两个点是否存在两条互不相同的路径可以互达(现在一条路径被箱子挡了,若另一条也存在就说明这次行动合法)。

这又等价于判定两个点是否在同一个点双联通分量中。

于是\(Tarjan\)预处理点双,由于一个点最多只有\(4\)条边,所以也最多属于\(4\)个点双,暴力判定即可,时间复杂度\(O(16^2nm)\),这样已经足以通过此题。

当然,我们可以把点双树或者圆方树建出来,判定两点树上距离是否小于等于\(1\)(圆方树上小于等于\(2\)),实现\(O(1)\)判定,时间复杂度\(O(16nm)\)。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 1520;
struct edge { int ver,next; } e[N*N*8],ec[N*N*8];
struct node
{
int x,y;
node (int _x = 0,int _y = 0) { x = _x , y = _y; }
friend node operator + (node p1,node p2) { return node(p1.x+p2.x,p1.y+p2.y); }
friend node operator - (node p1,node p2) { return node(p1.x-p2.x,p1.y-p2.y); }
friend bool operator == (node p1,node p2) { return p1.x == p2.x && p1.y == p2.y; }
} man,box;
struct state
{
node p; int dir;
state (node _p = node(0,0),int _dir = 0) { p = _p , dir = _dir; }
};
const node d[] = {node(0,1),node(1,0),node(-1,0),node(0,-1)};
int n,m,s,t,Head[N*N],Map[N][N],v[N][N],f[N][N][4];
int dfn[N*N],low[N*N],st[N*N],fa[N*N*2],num,cnt,top;
node S[4]; int scnt;
vector <int> bel[N*N];
inline void input(void)
{
scanf("%d%d%d",&n,&m,&s);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
char c = ' ';
while ( isspace(c) ) c = getchar();
if ( c == '#' ) Map[i][j] = 0;
else Map[i][j] = 1;
if ( c == 'A' ) man = node(i,j);
if ( c == 'B' ) box = node(i,j);
}
}
inline void insert(int x,int y) { e[++t] = (edge){y,Head[x]} , Head[x] = t; }
inline bool valid(node p) { return p.x >= 1 && p.y >= 1 && p.x <= n && p.y <= m && Map[p.x][p.y]; }
inline int index(node p) { return ( p.x - 1 ) * m + p.y; }
inline void build(void)
{
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
for (int k=0;k<4;k++)
if ( valid(node(i,j)) && valid(node(i,j)+d[k]) )
insert( index(node(i,j)) , index(node(i,j)+d[k]) );
}
inline void Tarjan(int x)
{
dfn[x] = low[x] = ++num;
st[++top] = x;
for (int i=Head[x];i;i=e[i].next)
{
int y = e[i].ver;
if ( !dfn[y] )
{
Tarjan( y );
low[x] = min( low[x] , low[y] );
if ( low[y] >= dfn[x] )
{
int z; ++cnt;
do z = st[top--] , fa[z] = cnt;
while ( z != y );
fa[cnt] = x;
}
}
else low[x] = min( low[x] , dfn[y] );
}
}
inline void Prebfs(void)
{
queue <node> q;
q.push( man ) , v[man.x][man.y] = true;
while ( !q.empty() )
{
node x = q.front(); q.pop();
for (int i=0;i<4;i++)
{
node y = x + d[i];
if ( y == box ) S[++scnt] = x;
if ( valid(y) && !( y == box ) && !v[y.x][y.y] )
v[y.x][y.y] = true , q.push(y);
}
}
}
inline bool belong(node x,node y)
{
if ( !valid(x) || !valid(y) ) return false;
int ix = index(x) , iy = index(y);
return fa[fa[ix]] == iy || fa[fa[iy]] == ix || fa[ix] == fa[iy];
}
inline void Bfs(void)
{
queue <state> q;
for (int i=1;i<=scnt;i++)
for (int j=0;j<4;j++)
if ( S[i] + d[j] == box )
q.push(state(box,j)) , f[box.x][box.y][j] = true;
while ( !q.empty() )
{
state x = q.front(); q.pop();
for (int i=0;i<4;i++)
{
node y = x.p + d[i];
if ( valid(y) && belong(x.p-d[x.dir],x.p-d[i]) && !f[y.x][y.y][i] )
f[y.x][y.y][i] = true , q.push( state(y,i) );
}
}
}
inline void solve(void)
{
for (int i=1;i<=s;i++)
{
int x,y;
scanf("%d%d",&x,&y);
bool ans = f[x][y][0] || f[x][y][1] || f[x][y][2] || f[x][y][3] || box == node(x,y);
puts( ans ? "YES" : "NO" );
}
}
int main(void)
{
freopen("pushbox.in","r",stdin);
freopen("pushbox.out","w",stdout);
input();
build();
cnt = n * m;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if ( Map[i][j] && !dfn[index(node(i,j))] )
Tarjan( index(node(i,j)) );
Prebfs();
Bfs();
solve();
return 0;
}

<后记>

『Pushbox 点双联通分量』的更多相关文章

  1. 『Tarjan算法 无向图的双联通分量』

    无向图的双连通分量 定义:若一张无向连通图不存在割点,则称它为"点双连通图".若一张无向连通图不存在割边,则称它为"边双连通图". 无向图图的极大点双连通子图被 ...

  2. 【UVA10972】RevolC FaeLoN (求边双联通分量)

    题意: 给你一个无向图,要求把所有无向边改成有向边,并且添加最少的有向边,使得新的有向图强联通. 分析: 这题的解法还是很好想的.先用边双联通分量缩点,然后找新图中入度为0和为1的点,入度为0则ans ...

  3. lightoj 1300 边双联通分量+交叉染色求奇圈

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1300 边双连通分量首先dfs找出桥并标记,然后dfs交叉着色找奇圈上的点.这题只要求在 ...

  4. HDU5409---CRB and Graph 2015多校 双联通分量缩点

    题意:一个联通的无向图, 对于每一条边, 若删除该边后存在两点不可达,则输出这两个点, 如果存在多个则输出第一个点尽可能大,第二个点尽可能小的. 不存在输出0 0 首先 若删除某一条边后存在多个联通分 ...

  5. poj2942(双联通分量,交叉染色判二分图)

    题意:一些骑士,他们有些人之间有矛盾,现在要求选出一些骑士围成一圈,圈要满足如下条件:1.人数大于1.2.总人数为奇数.3.有仇恨的骑士不能挨着坐.问有几个骑士不能和任何人形成任何的圆圈. 思路:首先 ...

  6. 大白书中无向图的点双联通分量(BCC)模板的分析与理解

    对于一个无向图,如果任意两点至少存在两条点不重复(除起点和终点外无公共点)的路径,则这个图就是点双联通. 这个要求等价于任意两条边都存在于一个简单环(即同一个点不能在圈中出现两次)中,即内部无割点. ...

  7. 洛谷P2860 [USACO06JAN]冗余路径Redundant Paths(tarjan求边双联通分量)

    题目描述 In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1. ...

  8. ARC062 - F. Painting Graphs with AtCoDeer (Polya+点双联通分量)

    似乎好久都没写博客了....赶快来补一篇 题意 给你一个 \(n\) 个点 , 没有重边和自环的图 . 有 \(m\) 条边 , 每条边可以染 \(1 \to k\) 中的一种颜色 . 对于任意一个简 ...

  9. Tarjan 强连通分量 及 双联通分量(求割点,割边)

    Tarjan 强连通分量 及 双联通分量(求割点,割边) 众所周知,Tarjan的三大算法分别为 (1)         有向图的强联通分量 (2)         无向图的双联通分量(求割点,桥) ...

随机推荐

  1. MQ选型对比ActiveMQ,RabbitMQ,RocketMQ,Kafka 消息队列框架选哪个?

    最近研究消息队列,发现好几个框架,搜罗一下进行对比,说一下选型说明: 1)中小型软件公司,建议选RabbitMQ.一方面,erlang语言天生具备高并发的特性,而且他的管理界面用起来十分方便.不考虑r ...

  2. Vue.js 源码分析(九) 基础篇 生命周期详解

    先来看看官网的介绍: 主要有八个生命周期,分别是: beforeCreate.created.beforeMount.mounted.beforeupdate.updated   .beforeDes ...

  3. Telegram APIs中文介绍

    Telegram APIs 我们为开发者提供了两种API,Bot API (机器人API) 允许你很轻松地用Telegram的接口创建程序,Telegram API 和DLib 允许你创建定制自己的T ...

  4. mybatis if-else用法

    demo: <select id="queryRuralCodes" resultType="string" parameterType="ma ...

  5. UE4 C++中出现的让人手足无措的问题(持续更新)

    最近开始涉入UE4更深层的一面——UE4 C++,由于其中的体系和在课本或者是网课上那么说的C++体系有一些误差(准确说就是遵循的C++标准不同),导致学习与运用起来有些吃力,所以作此总结,为自己的开 ...

  6. reduce计算数组中每个元素出现的次数 数组去重的几种方式 将多维数组转化为一维

    // js计算数组中每个元素出现的次数 // var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice']; // var countedNames = ...

  7. 201871010109-胡欢欢《面向对象程序设计(java)》第十三周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  8. shell 之for循环几种写法

    参见博客 http://blog.csdn.net/babyfish13/article/details/52981110 ,此博客写的非常清晰明了.

  9. 如何隐藏WooCommerce Shop Page页面的标题

    有时我们不想显示WooCommerce Shop Page页面标题,如下图所示,需要如何操作呢?随ytkah一起来看看吧.在主题function.php文件中添加下面的代码就可以隐藏了 add_fil ...

  10. JavaScript中的this—你不知道的JavaScript上卷读书笔记(三)

    this是什么? this 是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件.this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式.当一个函数被调用时,会 ...