『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) 无向图的双联通分量(求割点,桥) ...
随机推荐
- docker操作命令大全和后台参数
一.命令行 可以通过运行 docker ,或者 docker help 命令得到命令行的帮助信息(我们以 CentOS 为操作环境为例): [root@iz2ze2bn5x2wqxdeq65wlpz ...
- 第九届极客大挑战——怎么又是江师傅的秘密(java反序列化)
这道题其实是考jsp和java的,我没学过jsp,java倒是有一点了解,但是刚拿到题的时候还是看不懂java代码里的内容,所以去简单学习了下jsp(jsp教程),按照教程里的步骤搭建了eclipse ...
- 【APS系统应用案例】高博通信智能制造的新武器
企业背景: 早在2006年,一个年轻的企业瞄准国际高端航空产业及超精密制造行业.高博集团,以普世价值开创航空中国的新纪元. 高博通信(上海)有限公司(下文简称“高博通信”)占地36000平方米,以满足 ...
- 【转】合并两个List并去掉重复项
原文:https://my.oschina.net/jack90john/blog/1493170 工作中很多时候需要用到合并两个List并去除其中的重复内容.这是一个很简单的操作,这里主要是记录一下 ...
- Java垃圾回收。
一:如何确定哪些对象应该被回收. 1.引用记数法.在对象中添加一个引用计数器,每当有一个地方引用它时,计数器加一,引用失效时,计数器减一,当计数器为0时,该对象是不可用的. i:缺陷:会产生循环 ...
- 使用python实现后台系统的JWT认证
介绍 JWT协议似乎已经应用十分广泛,JSON Web Token--一种基于token的json格式web认证方法.基本的原理是,第一次认证通过用户名密码,服务端签发一个json格式的token.后 ...
- Python元组与字符串操作(8)——三数排序多种实现
练习 依次接收用户输入的3个数,排序后打印 1.转换int后,判断大小排序,使用分支结构完成 num1 = [] for i in range(3): num1.append(int(input('& ...
- python hash 哈希值
自增知识点 1,哈希 什么是可哈希(hashable)? 简要的说可哈希的数据类型,即不可变的数据结构(字符串str.元组tuple.对象集objects). 哈希有啥作用? 它是一个将大体量数据转化 ...
- 张兴盼-201871010131《面向对象程序设计(Java)》第七周学习总结
张兴盼-201871010131<面向对象程序设计(Java)>第七周学习总结 项目 内容 这个作业属于哪个课程 http://www.cnblogs.com/nwnu-daizh/ 这个 ...
- 201871010134-周英杰《面向对象程序设计(java)》第十五周学习总结
项目 内容 这个作业属于哪个课程 <任课教师博客主页链接>https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 <作业链接地址>http ...