P4082 题解

news/2025/2/8 22:49:31/文章来源:https://www.cnblogs.com/wf715/p/18705559/P4082

题目链接

题意:推箱子。给定一个 \(n \times m\) 的长方形地面,上面有若干障碍物,并给定箱子与人的位置,问哪些位置可以被人用箱子推到。

显然,对于一个局面,我们只关心箱子的位置和人可以出现在箱子的上下左右哪些方向。我们对每个格子设出四个点,分别表示箱子在这个格子上,且人能够走到它的上、下、左、右四个方向的状态。那么假设一个人在箱子的左边,且箱子的右边是空地,那么这个状态就可以转移到右边的格子且人在左边的状态,建一条有向边,以此类推。

但是人在箱子的某个方向时,也可能可以通过路径走到箱子的另一个方向,例如从箱子的左边走到上面。于是对于每个箱子的位置,我们要找出箱子在这个位置上时哪些方向是可以互相到达的。由于箱子在某个格子上相当于删掉了这个格子,使其不连通,我们考虑新建一张图,使每个格子变为一个点,并将箱子的初始位置也看作空地,在相邻的空地之间连边。那么我们在这张图上面跑点双,如果某个格子对应的点是割点,那么意味着当箱子在这个格子上时,会有某些空地无法互相到达,此时相邻的格子中只有在同一个点双里的才能够互相到达。于是我们建出圆方树,当某个格子是割点时就将相邻的四个格子判断一下是否处在同个点双中,是的话在前面表示状态的图上连双向边,而不是割点的显然周围的格子都能互相到达,取一个点与其他所有点连双向边即可。显然每个点与外面连的边的数量是 \(O(1)\) 的,所以最终状态图的边数是 \(O(nm)\) 的。

最后在人的初始位置 BFS 一次,找到人刚开始时能在箱子的哪个方向,把其置为 \(1\),然后从那个状态开始 BFS 即可。最后询问时若格子的四个方向状态有任意一个为 \(1\),或者就是箱子的初始位置,那么这个格子可以被用箱子推到,否则不行。时间复杂度 \(O(nm)\)

code:

#include <bits/stdc++.h>
#define in(x, y) ((x) >= 1 && (x) <= n && (y) >= 1 && (y) <= m)
#define tr(x, y) (((x) - 1) * m + (y))using namespace std;namespace Block {int cnt, head[4600000], to[10000000], nxt[10000000], dep[4600000], fa[4600000];void init() { memset(head, cnt = 0, sizeof(head)); }void add(int u, int v) {nxt[++cnt] = head[u];head[u] = cnt;to[cnt] = v;}void dfs(int g) {dep[g] = dep[fa[g]] + 1;for (int i = head[g]; i; i = nxt[i])if (to[i] ^ fa[g]) {fa[to[i]] = g;dfs(to[i]);}}bool eq(int x, int y) {if (dep[x] < dep[y])swap(x, y);if ((dep[y] ^ dep[x] - 2) && (dep[y] ^ dep[x]))return 0;else if (dep[y] == dep[x])return fa[x] == fa[y];elsereturn fa[fa[x]] == y;}
};namespace BFS {int tot, cnt, head[10000000], to[30000000], nxt[30000000];bool f[10000000];void init() { memset(head, tot = cnt = 0, sizeof(head)); }void add(int u, int v) {nxt[++cnt] = head[u];head[u] = cnt;to[cnt] = v;}void bfs(int s) {queue<int> q;int g;q.push(s);f[s] = 1;while (!q.empty()) {g = q.front();q.pop();for (int i = head[g]; i; i = nxt[i])if (!f[to[i]]) {q.push(to[i]);f[to[i]] = 1;}}}
};struct Node {int x, y;Node() { }Node(int _x, int _y): x(_x), y(_y) { }
};int n, m, q, ax, ay, bx, by, tot, scc, cnt, head[2300000], to[20000000], nxt[20000000], dfsn[2300000], low[2300000], st[2300000], ed, pos[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}, p[4], dy[1505][1505][4];
char s[1505][1505];
bool key[2300000], bv[1505][1505];void add(int u, int v) {nxt[++cnt] = head[u];head[u] = cnt;to[cnt] = v;
}void tarjan(int g, int fa) {int ch = 0;dfsn[g] = low[g] = ++tot;st[++ed] = g;for (int i = head[g]; i; i = nxt[i])if (!dfsn[to[i]]) {++ch;tarjan(to[i], g);low[g] = min(low[g], low[to[i]]);if (low[to[i]] >= dfsn[g]) {if (fa) key[g] = 1;++scc;while (st[ed] ^ to[i]) {Block::add(st[ed], scc), Block::add(scc, st[ed]);--ed;}Block::add(st[ed], scc), Block::add(scc, st[ed]);Block::add(g, scc), Block::add(scc, g);--ed;}} else if (to[i] ^ fa)low[g] = min(low[g], dfsn[to[i]]);if (!fa && ch > 1)key[g] = 1;
}void bfs() {queue<Node> q;Node g;q.push(Node(ax, ay));bv[ax][ay] = 1;while (!q.empty()) {g = q.front();q.pop();for (int i = 0; i < 4; ++i)if (s[g.x + pos[i][0]][g.y + pos[i][1]] == '.' && !bv[g.x + pos[i][0]][g.y + pos[i][1]]) {q.push(Node(g.x + pos[i][0], g.y + pos[i][1]));bv[g.x + pos[i][0]][g.y + pos[i][1]] = 1;}}
}int main() {Block::init(), BFS::init();scanf("%d %d %d", &n, &m, &q);scc = n * m;for (int i = 1; i <= n; ++i)scanf("\r\n%s", s[i] + 1);for (int i = 1; i <= n; ++i)for (int j = 1; j <= m; ++j)if (s[i][j] ^ '#') {if (j < m && (s[i][j + 1] ^ '#'))add(tr(i, j), tr(i, j + 1)), add(tr(i, j + 1), tr(i, j));if (i < n && (s[i + 1][j] ^ '#'))add(tr(i, j), tr(i + 1, j)), add(tr(i + 1, j), tr(i, j));if (s[i][j] == 'A')ax = i, ay = j;else if (s[i][j] == 'B')bx = i, by = j;}for (int i = 1; i <= n; ++i)for (int j = 1; j <= m; ++j)if ((s[i][j] ^ '#') && !dfsn[tr(i, j)]) {tarjan(tr(i, j), ed = 0);Block::dfs(tr(i, j));}for (int i = 1; i <= n; ++i)for (int j = 1; j <= m; ++j)if (s[i][j] ^ '#')for (int k = 0; k < 4; ++k)if (in(i + pos[k][0], j + pos[k][1]) && (s[i + pos[k][0]][j + pos[k][1]] ^ '#'))dy[i][j][k] = ++BFS::tot;for (int i = 1; i <= n; ++i)for (int j = 1, c = 0; j <= m; ++j, c = 0)if (s[i][j] ^ '#') {for (int k = 0; k < 4; ++k) {if (in(i + pos[k][0], j + pos[k][1]) && (s[i + pos[k][0]][j + pos[k][1]] ^ '#'))p[++c] = k;if (in(i - pos[k][0], j - pos[k][1]) && (s[i - pos[k][0]][j - pos[k][1]] ^ '#'))BFS::add(dy[i][j][k], dy[i - pos[k][0]][j - pos[k][1]][k]);}if (c > 1)if (!key[tr(i, j)])for (int k = 1; k < c; ++k)BFS::add(dy[i][j][p[k]], dy[i][j][p[k + 1]]), BFS::add(dy[i][j][p[k + 1]], dy[i][j][p[k]]);elsefor (int k = 1; k < c; ++k)for (int l = k + 1; l <= c; ++l)if (Block::eq(tr(i + pos[p[k]][0], j + pos[p[k]][1]), tr(i + pos[p[l]][0], j + pos[p[l]][1]))) {BFS::add(dy[i][j][p[k]], dy[i][j][p[l]]), BFS::add(dy[i][j][p[l]], dy[i][j][p[k]]);break;}}bfs();for (int i = 0; i < 4; ++i)if (bv[bx + pos[i][0]][by + pos[i][1]]) {BFS::bfs(dy[bx][by][i]);break;}while (q--) {scanf("%d %d", &ax, &ay);if (ax == bx && ay == by)puts("YES");elsefor (int i = 0; i < 5; ++i)if (i == 4)puts("NO");else if (BFS::f[dy[ax][ay][i]]){ puts("YES"); break; }}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/881014.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

08_LaTeX之自定义LaTeX命令和功能

本章的内容将让你能编写可重复利用的模块——宏包和文档类,并在其中自己定义命令和环境。08_\(\LaTeX{}\) 之自定义\(\LaTeX{}\)命令和功能 目录08_\(\LaTeX{}\) 之自定义\(\LaTeX{}\)命令和功能自定义命令和环境定义新命令定义环境xparse 宏包简介编写自己的宏包和文档类编写…

2024FJ省队集训 - 笔记 游记

Day 0 火车上写了两道可爱小清新数学题。题没写多少bug还一堆。 我们住的是福建省团校,据说是福州有演唱会导致各种酒店房间紧张。 和 wzh,zzp 口胡了一些题目就去睡觉了。 团校的住宿条件确实不错,睡得挺香。 Day 1 T1 提交答案题就是依托美味的构式,你T2T3费劲心思骗个五分…

Stern-Brocot 树

Stern-Brocot 树由两个初始值 \(0\over 1\) 和 \(1\over0\),由两个相邻的数 \(a\over b\) 和 \(c\over d\) 会生成数 \(a + c\over b + d\)。这由图片可以非常直观地看出。形态类似于一棵树。 每个点上有一个"三元组"\((a,b,c)\),\(\left(\dfrac{0}{1},\dfrac{1}{1…

电影解析之虾米解析

我们通常会因为看电影但是需要vip却没有足够生活费去支持的困扰 我就在想有没有白嫖的方法呢(bushi 就在我苦恼的时候我发现了一个方法————就是被称为:解析 的技术这玩意就是最好的选择 但是可能部分人在刚刚接触的时候不会用的于是我就写了一个小软件来支持(只支持wind…

【AI+安全】基于大模型在流量分析领域应用的实践

一、内容概要 随着网络攻击手段的不断进化,流量分析已经成为确保网络安全的关键环节。传统的基于规则和机器学习的方法在一定程度上帮助我们识别和防范攻击,但随着网络攻击形式的多样化和复杂性增加,如何利用更强大的技术手段来分析网络流量,成为了当今网络安全领域的研究热…

RocketMQ实战—7.生产集群部署和生产参数

大纲 1.RocketMQ生产集群部署和生产参数分析 2.RocketMQ生产集群10wTPS压测 3.RocketMQ生产级故障案例1.RocketMQ生产集群部署和生产参数分析 (1)服务器数量 4C8G阿⾥云⾼配服务器共四台,公⽹IP假设如下: 139.224.217.92,106.15.250.248,47.102.152.14,139.224.212.58 (2)…

十二、MyBatis分页插件

十二、MyBatis分页插件@目录十二、分页插件12.1 分页插件使用步骤12.2 分页插件的使用12.3 测试案例本人其他相关文章链接 十二、分页插件 12.1 分页插件使用步骤 1. 添加依赖 <dependency><groupId>com.github.pagehelper</groupId><artifactId>page…

htb Nunchucks walkthrough ssti + shebang绕过apparmor限制

注册发现注册失败扫描子域名 ffuf -u https://nunchucks.htb/ -w /usr/share/dirb/wordlists/common.txt -H "Host: FUZZ.nunchucks.htb" -fs 30589访问看看有啥随便输入个邮箱抓包看看 尝试ssti 注入发现确实存在在hacktrick上搜索payload https://book.hacktricks.…

P1551 亲戚

并查集还是不熟,还得练 #include<iostream> #include<set> #include<map> #include<algorithm> #include<vector> #define int long long const int N = 1e6; using namespace std; char* p1, * p2, buf[100000]; #define nc() (p1==p2 &&a…

推荐一些程序员常逛的开发者社区

前言 在信息技术日新月异的今天,程序员作为推动技术进步的重要力量,始终在探索、学习和交流的道路上不断前行。为了帮助程序员们更好地拓宽视野、提升技能,本文大姚将给大家推荐12个程序员常逛的开发者社区。 GitHub GitHub是一个功能强大、易于使用的代码托管平台。拥有庞大…

为飞牛OS基于FRP的内网穿透开启HTTPS加密

前言 玩NAS的朋友应该有比较多只是在家庭局域网使用,比如日常看看电影、备份手机照片什么的,这属于家庭局域网的使用场景。 当然了,如果你经常出差,或者过年回家不想把NAS也背回去,或者是想上班摸鱼,或者是NAS搭建游戏服务器之类的能公网访问就很有必要了。 公网访问我自…

0208《XEduHub + PySimpleGUI + PySimpleGUIWeb:在行空板上部署模型的全解析》【模型部署】

- 2月8日,晚上,19:30~21:00(主讲老师:邱奕盛)实验内容: 【模型部署】利用统一推理框架实现模型部署。 在训练好的模型基础上,设计简洁的体验界面, 最终尝试在行空板上实现完整效果的呈现,涉及 XEduHub、PySimpleGUI、PySimpleGUIWeb等工具。 import PySimpleGUI as …