【BZOJ5138】[Usaco2017 Dec]Push a Box(强连通分量)

题面

BZOJ

洛谷

题解

这题是今天看到萝卜在做然后他一眼秒了,我太菜了不会做,所以就来做做。

首先看完题目,是不是有点像\(NOIP\)的那道华容道?

所以类似的考虑状态\(f[x][y][d]\),表示当前箱子在\((x,y)\)位置,人在\(d\)(上下左右中的一个)方向时是否存在。那么这样子的状态数是\(4nm\)个,显然是可以的。考虑转移的话就是人推箱子了,沿着某个方向直接推是很容易的,现在的问题是如何让箱子不懂,换个方向。显然,如果箱子不动,人要换个方向的话,那么必定需要存在一条路径可以让人从一个方向走到另外一个方向,而箱子必定阻断了一条路径,所以等价于两个方向所在的点必定在一个点双内。那么把箱子扔掉,考虑所有空位置构成的点双,然后\(bfs\)一遍判断能否达到的所有位置即可。

然后是傻逼yyb调了2h,然而竟然是把一个变量yy写成了y。yyb习惯性连打两个y

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<vector>
  8. #include<queue>
  9. using namespace std;
  10. #define ll long long
  11. #define MAX 1555
  12. inline int read()
  13. {
  14. int x=0;bool t=false;char ch=getchar();
  15. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  16. if(ch=='-')t=true,ch=getchar();
  17. while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  18. return t?-x:x;
  19. }
  20. int n,m,q,dfn[MAX*MAX],low[MAX*MAX],tim,S[MAX*MAX],top,tot,cnt;
  21. int sx,sy,ex,ey,f[MAX][MAX][4];
  22. bool vis[MAX][MAX];
  23. char g[MAX][MAX];
  24. int bh[MAX][MAX];
  25. vector<int> G[MAX*MAX];
  26. int d[4][2]={-1,0,1,0,0,-1,0,1};
  27. struct Node{int x,y,d;};
  28. queue<Node> Q;
  29. void Tarjan(int x,int y,int fx,int fy)
  30. {
  31. dfn[bh[x][y]]=low[bh[x][y]]=++tim;S[++top]=bh[x][y];
  32. for(int i=0;i<4;++i)
  33. {
  34. int xx=x+d[i][0],yy=y+d[i][1];
  35. if(g[xx][yy]=='#')continue;
  36. if(xx==fx&&fy==yy)continue;
  37. if(!dfn[bh[xx][yy]])
  38. {
  39. Tarjan(xx,yy,x,y);
  40. low[bh[x][y]]=min(low[bh[x][y]],low[bh[xx][yy]]);
  41. if(low[bh[xx][yy]]>=dfn[bh[x][y]])
  42. {
  43. ++cnt;int v;
  44. do{G[v=S[top--]].push_back(cnt);}while(v!=bh[xx][yy]);
  45. G[bh[x][y]].push_back(cnt);
  46. }
  47. }
  48. else
  49. low[bh[x][y]]=min(low[bh[x][y]],dfn[bh[xx][yy]]);
  50. }
  51. }
  52. void BFS1()
  53. {
  54. Q.push((Node){sx,sy,0});vis[sx][sy]=true;
  55. while(!Q.empty())
  56. {
  57. Node u=Q.front();Q.pop();
  58. for(int i=0;i<4;++i)
  59. {
  60. int x=u.x+d[i][0],y=u.y+d[i][1];
  61. if(g[x][y]=='#')continue;
  62. if(x==ex&&y==ey){f[ex][ey][i^1]=true;continue;}
  63. if(vis[x][y])continue;
  64. vis[x][y]=true;Q.push((Node){x,y,0});
  65. }
  66. }
  67. }
  68. bool check(int a,int b,int x,int y)
  69. {
  70. for(int i=0,l1=G[bh[a][b]].size();i<l1;++i)
  71. for(int j=0,l2=G[bh[x][y]].size();j<l2;++j)
  72. if(G[bh[a][b]][i]==G[bh[x][y]][j])
  73. return true;
  74. return false;
  75. }
  76. void BFS2()
  77. {
  78. for(int i=0;i<4;++i)if(f[ex][ey][i])Q.push((Node){ex,ey,i});
  79. while(!Q.empty())
  80. {
  81. Node u=Q.front();Q.pop();
  82. //1.转到其它方向上面去
  83. for(int i=0;i<4;++i)
  84. {
  85. if(f[u.x][u.y][i])continue;
  86. int x=u.x+d[i][0],y=u.y+d[i][1];
  87. if(g[x][y]=='#')continue;
  88. if(check(u.x+d[u.d][0],u.y+d[u.d][1],x,y))
  89. f[u.x][u.y][i]=true,Q.push((Node){u.x,u.y,i});
  90. }
  91. //2.推一步
  92. int x=u.x+d[u.d^1][0],y=u.y+d[u.d^1][1];
  93. if(g[x][y]!='#')
  94. if(!f[x][y][u.d])
  95. f[x][y][u.d]=true,Q.push((Node){x,y,u.d});
  96. }
  97. }
  98. int main()
  99. {
  100. n=read();m=read();q=read();
  101. memset(g,'#',sizeof(g));
  102. for(int i=1;i<=n;++i)scanf("%s",g[i]+1),g[i][m+1]='#';
  103. for(int i=1;i<=n;++i)
  104. for(int j=1;j<=m;++j)
  105. if(g[i][j]=='A')sx=i,sy=j,g[i][j]='.';
  106. else if(g[i][j]=='B')ex=i,ey=j,g[i][j]='.';
  107. for(int i=1;i<=n;++i)
  108. for(int j=1;j<=m;++j)
  109. if(g[i][j]!='#')bh[i][j]=++tot;
  110. Tarjan(sx,sy,0,0);
  111. BFS1();BFS2();
  112. while(q--)
  113. {
  114. int x=read(),y=read();bool fl=(x==ex)&&(y==ey);
  115. for(int i=0;i<4;++i)fl|=f[x][y][i];
  116. puts(fl?"YES":"NO");
  117. }
  118. return 0;
  119. }

【BZOJ5138】[Usaco2017 Dec]Push a Box(强连通分量)的更多相关文章

  1. bzoj5138 [Usaco2017 Dec]Push a Box

    题目描述: bz luogu 题解: 暴力可以记录$AB$位置转移,这个时候状态是$n^4$的,无法接受. 考虑只记录$A$在$B$旁边时的状态,这个时候状态时$n^2$的. 所以说转移有两种,一种是 ...

  2. 有向图的强连通分量的求解算法Tarjan

    Tarjan算法 Tarjan算法是基于dfs算法,每一个强连通分量为搜索树中的一颗子树.搜索时,把当前搜索树中的未处理的结点加入一个栈中,回溯时可以判断栈顶到栈中的结点是不是在同一个强连通分量中.当 ...

  3. 有向图强连通分量的Tarjan算法

    有向图强连通分量的Tarjan算法 [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G ...

  4. poj2186Popular Cows(Kosaraju算法--有向图的强连通分量的分解)

    /* 题目大意:有N个cows, M个关系 a->b 表示 a认为b popular:如果还有b->c, 那么就会有a->c 问最终有多少个cows被其他所有cows认为是popul ...

  5. 强连通分量的Tarjan算法

    资料参考 Tarjan算法寻找有向图的强连通分量 基于强联通的tarjan算法详解 有向图强连通分量的Tarjan算法 处理SCC(强连通分量问题)的Tarjan算法 强连通分量的三种算法分析 Tar ...

  6. HD2767Proving Equivalences(有向图强连通分量+缩点)

    题目链接 题意:有n个节点的图,现在给出了m个边,问最小加多少边是的图是强连通的 分析:首先找到强连通分量,然后把每一个强连通分量缩成一个点,然后就得到了一个DAG.接下来,设有a个节点(每个节点对应 ...

  7. HDU4971 A simple brute force problem.(强连通分量缩点 + 最大权闭合子图)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4971 Description There's a company with several ...

  8. HDU 3072 (强连通分量)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3072 题目大意:为一个有向连通图加边.使得整个图全连通,有重边出现. 解题思路: 先用Tarjan把 ...

  9. 【BZOJ1051】1051: [HAOI2006]受欢迎的牛 tarjan求强连通分量+缩点

    Description 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认 ...

随机推荐

  1. ASP.NET Core的Kestrel服务器(转载)

    Kestrel是一个基于libuv的跨平台ASP.NET Core web服务器,libuv是一个跨平台的异步I/O库.ASP.NET Core模板项目使用Kestrel作为默认的web服务器.Kes ...

  2. 现有工程中集成Cordova

    cocoapods引入cordova源码 1.依赖Cordova和wk插件 pod 'Cordova' pod 'cordova-plugin-wkwebview-engine' 建立Cordova支 ...

  3. 20155218《网络对抗》Exp2 后门原理与实践

    20155218<网络对抗>Exp2 后门原理与实践 常用后门工具实践 1.Windows获得Linux Shell: 在Windows下,先使用ipconfig指令查看本机IP,使用nc ...

  4. python 回溯法 子集树模板 系列 —— 8、图的遍历

    问题 一个图: A --> B A --> C B --> C B --> D B --> E C --> A C --> D D --> C E -- ...

  5. 利用OVS+FLOODLIGHT,为数据表添加VLAN_ID和MPLS

    话不多说,直接上拓扑: 我这里是用主机h1 (10.0.0.1)ping 主机h2(10.0.0.2) 1.添加VLAN标签 v1: sudo ovs-ofctl add-flow m1-s1 in_ ...

  6. idea git pull项目到本地时容易出现的问题

    有时候pull到本地,出了各种错误,其实是因为搞来搞去的,容易出问题,所以最好的方法是拿原有打包好的整个稳定能跑的项目环境, 先git add,然后vcs重置head为hard,然后再pull,一般就 ...

  7. JavaScript快速入门-ECMAScript本地对象(String)

    一.String对象 String对象和python中的字符串一样,也有很多方法,这些方法大概分为以下种类: 1.索引和查找 1.charAt()   返回指定位置的字符. 2.charCodeAt( ...

  8. vue基础项目安装教程

    安装node.js 从node.js官网下载并安装node,安装过程很简单,一路“下一步”就可以了. 安装完成之后,打开命令行工具,输入 node -v,如下图,如果出现相应的版本号,则说明安装成功. ...

  9. 百度地图API的网页使用

    请看图示(以及参考官方文档): 图片尺寸:1710x822

  10. svn commit时报错 File already exists

    第一步: 删除当前文件所在文件夹,提交commit 第二步: 新建刚才删除的文件夹,并将先前需要commit的文件放到此文件夹下,再次commit 提交