『Pushbox 点双联通分量』
<更新提示>
<第一次更新>
<正文>
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 点双联通分量』的更多相关文章
- 『Tarjan算法 无向图的双联通分量』
无向图的双连通分量 定义:若一张无向连通图不存在割点,则称它为"点双连通图".若一张无向连通图不存在割边,则称它为"边双连通图". 无向图图的极大点双连通子图被 ...
- 【UVA10972】RevolC FaeLoN (求边双联通分量)
题意: 给你一个无向图,要求把所有无向边改成有向边,并且添加最少的有向边,使得新的有向图强联通. 分析: 这题的解法还是很好想的.先用边双联通分量缩点,然后找新图中入度为0和为1的点,入度为0则ans ...
- lightoj 1300 边双联通分量+交叉染色求奇圈
题目链接:http://lightoj.com/volume_showproblem.php?problem=1300 边双连通分量首先dfs找出桥并标记,然后dfs交叉着色找奇圈上的点.这题只要求在 ...
- HDU5409---CRB and Graph 2015多校 双联通分量缩点
题意:一个联通的无向图, 对于每一条边, 若删除该边后存在两点不可达,则输出这两个点, 如果存在多个则输出第一个点尽可能大,第二个点尽可能小的. 不存在输出0 0 首先 若删除某一条边后存在多个联通分 ...
- poj2942(双联通分量,交叉染色判二分图)
题意:一些骑士,他们有些人之间有矛盾,现在要求选出一些骑士围成一圈,圈要满足如下条件:1.人数大于1.2.总人数为奇数.3.有仇恨的骑士不能挨着坐.问有几个骑士不能和任何人形成任何的圆圈. 思路:首先 ...
- 大白书中无向图的点双联通分量(BCC)模板的分析与理解
对于一个无向图,如果任意两点至少存在两条点不重复(除起点和终点外无公共点)的路径,则这个图就是点双联通. 这个要求等价于任意两条边都存在于一个简单环(即同一个点不能在圈中出现两次)中,即内部无割点. ...
- 洛谷P2860 [USACO06JAN]冗余路径Redundant Paths(tarjan求边双联通分量)
题目描述 In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1. ...
- ARC062 - F. Painting Graphs with AtCoDeer (Polya+点双联通分量)
似乎好久都没写博客了....赶快来补一篇 题意 给你一个 \(n\) 个点 , 没有重边和自环的图 . 有 \(m\) 条边 , 每条边可以染 \(1 \to k\) 中的一种颜色 . 对于任意一个简 ...
- Tarjan 强连通分量 及 双联通分量(求割点,割边)
Tarjan 强连通分量 及 双联通分量(求割点,割边) 众所周知,Tarjan的三大算法分别为 (1) 有向图的强联通分量 (2) 无向图的双联通分量(求割点,桥) ...
随机推荐
- Outlook API
1.Outlook简介 若要从Outlook 外控制Outlook对象,必须在编写代码的工程中建立对Outlook对象库的引用. 1.1 Outlook Application说明: 代表整个Mic ...
- 【Android】天气应用
模仿华为的"天气"应用写的一个小Demo.部分功能.动画效果没有实现,也没有过多考虑性能.Bug等其它方面的因素.写这个Demo的初衷是想熟悉下目前网上常用的一些框架. Demo采 ...
- Hibernate基于注解实现自关联树形结构实现
很久没用过Hibernate了,项目需求需要使用,并建立树形结构,在开发中遇到一些问题,在这里记录一下. 1.创建数据库表,主要是设置标志信息,不然插入数据库会报id不能插入null的错误. 2.创建 ...
- SQL Server 使用union all查询多个条件数据合并分组显示,同比统计
),a.created_yearmonth,) created_yearmonth, a.countaccount countaccount, a.yxsl yxsl, a.sccdsl sccdsl ...
- linux重要的配置文件列表
启动引导程序配置文件 LILO /etc/lilo.conf GRUB /boot/grub/menu.lst 系统启动文件核脚本 主启动控制文件 /etc/inittab SysV启动脚本的位置 / ...
- 终端的乐趣--Linux下有趣的终端命令或者工具【转】
转自:https://blog.csdn.net/gatieme/article/details/52144603 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原 ...
- 第15节_BLE协议GATT层
学习资料:官方手册 Vol 3: Core System Package [Host volume] Part G: Generic Attribute Profile (GATT) 这篇文章格式比较 ...
- robotframework-post request请求携带上一个请求返回的cookie
公司的接口服务需要先登录,获取服务端的cookie后,在后续的请求中携带这个cookie才能够访问 在尝试用RF工具进行自动化接口测试时,发现先访问登录接口之后,接着请求其他接口时没有自动携带上次请求 ...
- 交互器中python中的帮助使用
C:\Users\ceshi>pythonPython 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:24:40) [MSC v.1500 64 b ...
- git push origin master错误
以下错误是因为远程有的文件,本地没有,故而无法push文件到远程 $ git push origin master To git@github.com:AntonioSu/learngitWindow ...