<更新提示>

<第一次更新>


<正文>

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. 【Android】天气应用

    模仿华为的"天气"应用写的一个小Demo.部分功能.动画效果没有实现,也没有过多考虑性能.Bug等其它方面的因素.写这个Demo的初衷是想熟悉下目前网上常用的一些框架. Demo采 ...

  2. Mac下多版本pip共存

    Mac下多版本pip共存 来自于官方的解释, pip是python包管理工具, 该工具提供了对python包的查找, 下载, 安装, 卸载等功能python第三方工具包多数依赖于pip进行安装, 如 ...

  3. vue3.0创建项目和基本配置

    借鉴博客:https://www.jianshu.com/p/6307c568832d/ https://www.cnblogs.com/KenFine/p/10850386.html 项目创建好后, ...

  4. 查看 JVM 默认参数

    -XX:+PrintFlagsFinal 可以获取所有可设置参数及值 获取 JVM 默认 Xss 大小 java -XX:+PrintFlagsFinal -version | grep Thread ...

  5. springboot测试启动报错java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test

    springboot测试启动报错: java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you ne ...

  6. tornado 之 RequestHandler(请求)

    RequestHandler from tornado.web import ReuqestHandler 一.利用HTTP协议想服务器传递参数 提取url的特定部分 http://127.0.0.1 ...

  7. Nginx内置变量以及日志格式变量

    $args #请求中的参数值$query_string #同 $args$arg_NAME #GET请求中NAME的值$is_args #如果请求中有参数,值为"?",否则为空字符 ...

  8. 怎么在虚拟机下的Linux系统安装数据库

    1.查看 linux下是否有老版本的mysql(有删除) 查找old mysql:rpm -qa | grep mysql 卸载:卸载命令:rpm –ev {包名}——:rpm -ev mysql-c ...

  9. 反射&异常

    反射 通过字符串映射或修改程序运行时的状态.属性.方法.python中的反射功能是由以下四个内置函数提供:hasattr.getattr.setattr.delattr,改四个函数分别用于对对象内部执 ...

  10. NOIP 2002 过河卒

    洛谷P1002 https://www.luogu.org/problemnew/show/P1002 JDOJ 1290 https://neooj.com/oldoj/problem.php?id ...