bzoj5138 [Usaco2017 Dec]Push a Box
题目描述:
题解:
暴力可以记录$AB$位置转移,这个时候状态是$n^4$的,无法接受。
考虑只记录$A$在$B$旁边时的状态,这个时候状态时$n^2$的。
所以说转移有两种,一种是$A$推$B$一下,另一种是$A$绕到$B$另一侧。
第一种转移显然$O(1)$,瓶颈在第二种。
发现这对点满足点双,所以建出广义圆方树,判两个点是否同父亲或一个点是另一个点的爷爷。
时间复杂度$O(n^2)$。
代码:
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = ;
template<typename T>
inline void read(T&x)
{
T f = ,c = ;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){c=c*+ch-'';ch=getchar();}
x = f*c;
}
int n,m,Q,nam[N][N],tot,rtx,rty,rt,stx,sty,st,hed[N*N],cnt=;
char mp[N][N];
bool check(int x,int y){return x&&y&&x<=n&&y<=m;}
int dx[]={-,,,},dy[]={,,-,};
struct EG
{
int to,nxt;
}e[*N*N];
void ae(int f,int t)
{
e[++cnt].to = t;
e[cnt].nxt = hed[f];
hed[f] = cnt;
}
int dfn[N*N],low[N*N],tim,fa[N*N*];
int sta[N*N*],tl;
void tarjan(int u,int f)
{
dfn[u] = low[u] = ++tim;
sta[++tl] = u;
for(int j=hed[u];j;j=e[j].nxt)
{
int to = e[j].to;
if(to==f)continue;
if(!dfn[to])
{
tarjan(to,u);
low[u] = min(low[u],low[to]);
if(low[to]>=dfn[u])
{
int now = ++tot;
fa[now] = u;
int c = -;
while(c!=to)
{
c = sta[tl--];
fa[c] = now;
}
}
}else low[u] = min(low[u],dfn[to]);
}
}
bool ck(int u,int v)
{
if(fa[u]==fa[v])return ;
if(fa[fa[v]]==u)return ;
if(fa[fa[u]]==v)return ;
return ;
}
bool dp[N][N][];
bool vis[N][N];
struct Pair
{
int x,y;
Pair(){}
Pair(int x,int y):x(x),y(y){}
};
void bfs()
{
queue<Pair>q;
q.push(Pair(rtx,rty));
vis[rtx][rty] = ;
while(!q.empty())
{
Pair tp = q.front();q.pop();
int x = tp.x,y = tp.y;
for(int k=;k<;k++)
{
int xx = x+dx[k],yy = y+dy[k];
if(!nam[xx][yy])continue;
if(xx==stx&&yy==sty)dp[stx][sty][k]=;
else if(!vis[xx][yy])vis[xx][yy]=,q.push(Pair(xx,yy));
}
}
}
struct Tri
{
int x,y,z;
Tri(){}
Tri(int x,int y,int z):x(x),y(y),z(z){}
};
void sol()
{
queue<Tri>q;
for(int k=;k<;k++)if(dp[stx][sty][k])
q.push(Tri(stx,sty,k));
while(!q.empty())
{
Tri tp = q.front();
q.pop();
int x = tp.x,y = tp.y,k = tp.z;
if(nam[x+dx[k]][y+dy[k]]&&!dp[x+dx[k]][y+dy[k]][k])dp[x+dx[k]][y+dy[k]][k]=,q.push(Tri(x+dx[k],y+dy[k],k));
for(int i=;i<;i++)if(nam[x-dx[i]][y-dy[i]]&&i!=k&&ck(nam[x-dx[k]][y-dy[k]],nam[x-dx[i]][y-dy[i]])&&!dp[x][y][i])
dp[x][y][i]=,q.push(Tri(x,y,i));
}
}
bool cck(int x,int y){return dp[x][y][]||dp[x][y][]||dp[x][y][]||dp[x][y][]||(x==stx&&y==sty);}
int main()
{
// freopen("tt.in","r",stdin);
read(n),read(m),read(Q);
for(int i=;i<=n;i++)
{
scanf("%s",mp[i]+);
for(int j=;j<=m;j++)if(mp[i][j]!='#')
{
nam[i][j] = ++tot;
if(mp[i][j]=='A')rt=tot,rtx=i,rty=j;
if(mp[i][j]=='B')st=tot,stx=i,sty=j;
}
}
for(int i=;i<=n;i++)for(int j=;j<=m;j++)if(mp[i][j]!='#')
{
int u = nam[i][j];
for(int x,y,k=;k<;k++)
{
x = i+dx[k],y = j+dy[k];
if(!check(x,y)||mp[x][y]=='#')continue;
ae(u,nam[x][y]);
}
}
tarjan(rt,);
bfs();sol();
for(int x,y,i=;i<=Q;i++)
{
read(x),read(y);
puts(cck(x,y)?"YES":"NO");
}
return ;
}
bzoj5138 [Usaco2017 Dec]Push a Box的更多相关文章
- 【BZOJ5138】[Usaco2017 Dec]Push a Box(强连通分量)
[BZOJ5138][Usaco2017 Dec]Push a Box(强连通分量) 题面 BZOJ 洛谷 题解 这题是今天看到萝卜在做然后他一眼秒了,我太菜了不会做,所以就来做做. 首先看完题目,是 ...
- BZOJ5142: [Usaco2017 Dec]Haybale Feast(双指针&set)(可线段树优化)
5142: [Usaco2017 Dec]Haybale Feast Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 182 Solved: 131[ ...
- luogu P4082 [USACO17DEC]Push a Box
传送门 一个人推箱子,和之前的华容道中的棋子移动有异曲同工之妙,因为每次可以让人走到箱子的其他方向上,或者推一下箱子 所以状态可以设成\(f_{i,j,k}\),即箱子在\((i,j)\),人在\(k ...
- [Usaco2017 Dec] A Pie for a Pie
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=5140 [算法] 最短路 时间复杂度 : O(N^2) [代码] #include&l ...
- [USACO17DEC]Push a Box
https://www.zybuluo.com/ysner/note/1293166 题面 戳我 解析 挺不错的一道图论码量题. 可以借此回顾一下\(noip2013\)华容道. 思路和华容道差不多. ...
- Luogu P4082 [USACO17DEC]Push a Box 点双连通分量/圆方树
(貌似有圆方树的做法,我写的是点双) 显然这道题就是直接搜索.定义状态为f[i][j][0~4]表示箱子在(i,j),人在某个方向推.然后问题就是怎么转向.我们发现如果要转向,必须是人走过一条不包括( ...
- BZOJ5142: [Usaco2017 Dec]Haybale Feast 线段树或二分答案
Description Farmer John is preparing a delicious meal for his cows! In his barn, he has NN haybales ...
- [BZOJ5139][Usaco2017 Dec]Greedy Gift Takers 权值线段树
Description Farmer John's nemesis, Farmer Nhoj, has NN cows (1≤N≤10^5), conveniently numbered 1…N. T ...
- BZOJ5137[Usaco2017 Dec]Standing Out from the Herd
看了半天题 不知道怎么用SAM维护 于是借(chao)鉴(xi)的一发神犇的 只要判断这个子串之前被标记的记号(也就是他属于第几个串)和这次转移到的是否相同 如果不同就说明该子串属于多个串 直接标记- ...
随机推荐
- [Xcode 实际操作]九、实用进阶-(5)使用正则表达式判断格式是否正确
目录:[Swift]Xcode实际操作 本文将演示使用正则表达式判断邮箱的格式是否正确. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit ...
- 异常定义-Mybatis中的源码参考
public class IbatisException extends RuntimeException { private static final long serialVersionUID = ...
- 《Python网络爬虫之三种数据解析方式》
引入 回顾requests实现数据爬取的流程 指定url 基于requests模块发起请求 获取响应对象中的数据 进行持久化存储 其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指 ...
- 使用express+mongoDB搭建多人博客 学习(4)登录与登出
登录 修改index.ejs <%- include header %> <% if(locals.error){ %> <span><%= locals.e ...
- 17999 Light-bot 模拟 + kmp求循环节
http://acm.scau.edu.cn:8000/uoj/mainMenu.html 17999 Light-bot 时间限制:1000MS 内存限制:65535K 提交次数:0 通过次数:0 ...
- box-shadow四周阴影
box-shadow 前面两个值为 纵向阴影 和 横向阴影 把这两个值都设置为 0 就是四边都有阴影 border:#074A99 0px solid; box-shadow: 0 0 10px #0 ...
- linux学习-Linux系统启动过程
linux系统启动过程 Linux系统的启动过程并不是大家想象中的那么复杂,其过程可以分为5个阶段: 内核的引导. 运行init. 系统初始化. 建立终端 . 用户登录系统. 内核引导 电源开机后,首 ...
- Solr6+IKAnalyzer分词环境搭建
环境要求 Zookeeper版本:zookeeper-3.4.8 JDK版本: jdk1.8. Solr版本:solr-6.4.1 Tomcat版本:tomcat8 ZK地址:127.0.0.1:21 ...
- Ubuntu16.04 + cuda8.0 + GTX1080安装教程
1. 安装Ubuntu16.04 不考虑双系统,直接安装 Ubuntu16.04,从 ubuntu官方 下载64位版本: ubuntu-16.04-desktop-amd64.iso . 在MAC下制 ...
- iOS --runtime理解
iOS~runtime理解 Runtime是想要做好iOS开发,或者说是真正的深刻的掌握OC这门语言所必需理解的东西.最近在学习Runtime,有自己的一些心得,整理如下,一为 查阅方便二为 或许能给 ...