【BZOJ - 2574】[Poi1999] Store-Keeper(点双连通分量,求割点,记忆化bfs)

题干:

有一个仓库被分成n*m 个矩形区域,如果两个区域有一条公共边,则被认为这两个区域相邻。包裹都放在一个区域中,剩余的区域或者空闲或者被集装箱占有,这是因为集装箱太重,仓库管理员不能将集装箱搬走。仓库管理员目是是要将包裹从开始的P区域移动到最后的K区域。他可以从空区域走到与之相邻的一个空区域。当仓库管理员走到与包裹相邻的区域时,它可以推动包裹,具体的推动方法如下所示:

 读入一个储藏表,开始位置为仓库管理员,最后位置为包裹移动的位置

Input

S – 集装箱,

M –仓库管理员的位置,

P –包裹开始的位置,

K –包裹最后的位置,

w –空区域. 

S, M, P 和 K 在文件中只出现一次.

第一行有两个用单个空格分隔的正整数n,m<=100. 接下来是货物存放二维表.共N行,每行为M 个字母组成的单词,字母分别是S, M, P, K, w. 第i单词的第j个位置表示第i行第j列区域的信息,可能是如下内容: 

Output

如果包裹不能移动到目的位置,则写入NO。

如果包裹能移动到目的位置,则写入最小的移动次数。

Sample Input

10 12

SSSSSSSSSSSS

SwwwwwwwSSSS

SwSSSSwwSSSS

SwSSSSwwSKSS

SwSSSSwwSwSS

SwwwwwPwwwww

SSSSSSSwSwSw

SSSSSSMwSwww

SSSSSSSSSSSS

SSSSSSSSSSSS

Sample Output

7

题目大意:

 中文题意。

解题报告:

这道题描述的是我们玩过的经典的小游戏,推箱子。由于要求步数最少,基本的想法是BFS,记录人的位置和箱子的位置两个状态。但是状态数过多,有100*100*100*100,进一步思考可以发现记录人的绝对位置是没有必要的,因为只有人在箱子旁边的单元格内,才能推箱子,所以只需记录箱子的位置和人在箱子的方向,只有100100*4个状态。
考虑bfs出所有可以到达的状态,O(1)回答询问。 
用f[x][y][i]表示箱子在(x,y),人在箱子的i方向。(人不在箱子旁时没啥用,所以可以压缩状态) 
两种转移:(一般来讲先动箱子再换人的方向)
1、推箱子,很好转移。 
2、箱子不动,人换方向。 

因为题目意思是:只有箱子动了一步,才算是移动次数+1.而人的移动不算移动次数,也就是说只需要考虑两点是否存在不经过箱子的路径,而不需要考虑最短路径是多少。

一个题解:

可以预处理出所有的点双来快速判断。因为这两点一定至少连通,所以如果两点都在一个点双里就可以。否则一定不可以。 
怎么判断两点是否同在一个点双中呢qaq,就是圆方树上这两点距离为2即可。不过好像内存开不下,时间多个log也吃不消。我们发现其实随便记一下父亲就可以O(1)了qaq。 
复杂度O(nm)

另一个题解:

进一步思考,发现两地如果连通,必须至少存在一条路径,如果总是连通,必须至少存在两条路径。也就是说,无论箱子作为障碍挡在哪条路径上,总还有另一条路径使这两点连通。这恰好是图论中双连通分支(点双连通)的定义,即没有割点的连通分支。所以可以这样判断,对于一个连通图,如果箱子不在割点上,箱子旁边的两点(人的位置)一定连通,如果箱子在割点上,则人的两点位置是否连通,取决于两点是否同属一个双连通分支。于是我们可以预处理出图中的所有割点和双连通分支,然后每次判断两点连通只需O(1)的时间。这样就可以解决这道题了。

AC代码:(因为没法交不上题所以贴一个网上的代码过来链接)(但是好像注释的那几行,用没注释的那个就可以过,用了就过不了)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 110
inline int read() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x*f;
}
int n,m,Q,id[N][N],h[N*N],num=0,f[N][N][4],owo=0,sx,sy,bx,by,tx,ty;
int dx[]= {0,-1,1,0},dy[]= {-1,0,0,1}; //0--往左推,1--上,2--下,3--右
char s[N];bool vis[N][N];
int dfn[N*N],low[N*N],dfnum=0,bel[N*N],ofo=0,fa[N*N];
bool isge[N*N]; 
struct edge {int to,next;
} data[N*N*4];
struct Icefox {int x,y,op;Icefox(int _x,int _y,int _op=0) {x=_x;y=_y;op=_op;}
};
inline void add(int x,int y){data[++num].to=y;data[num].next=h[x];h[x]=num;data[++num].to=x;data[num].next=h[y];h[y]=num;
}
stack<int>qq;
inline void tarjan(int x,int Fa) {dfn[x]=low[x]=++dfnum;qq.push(x);for(int i=h[x]; i; i=data[i].next) {int y=data[i].to;if(y==Fa) continue;if(!dfn[y]) {tarjan(y,x);low[x]=min(low[x],low[y]);if(low[y]<dfn[x]) continue;++ofo;fa[ofo]=x;isge[x]=1;while(1) {int z=qq.top();qq.pop();bel[z]=ofo;if(z==y) break;}continue;} low[x]=min(low[x],dfn[y]);}
}
inline bool jud(int x,int y,int z) {return bel[x]==bel[y]||fa[bel[x]]==y||fa[bel[y]]==x;//用下面那两行就过不了,不知道为什么
//	if(isge[z]==1) return bel[x]==bel[y];
//	else return 1;
}
int main() {n=read();m=read();for(int i=1; i<=n; ++i) {scanf("%s",s+1);for(int j=1; j<=m; ++j) {if(s[j]=='S') continue;id[i][j]=++owo;if(s[j]=='M') sx=i,sy=j;if(s[j]=='P') bx=i,by=j;if(s[j]=='K') tx=i,ty=j;for(int k=0; k<2; ++k) {int x=i+dx[k],y=j+dy[k];if(x<1||x>n||y<1||y>m||!id[x][y]) continue;add(id[i][j],id[x][y]);//直接就是加双向边 }}}for(int i=1; i<=owo; ++i) if(!dfn[i]) tarjan(i,0);memset(f,-1,sizeof(f));queue<Icefox>q;q.push(Icefox(sx,sy));vis[sx][sy]=1;while(!q.empty()) {int x=q.front().x,y=q.front().y;q.pop();for(int i=0; i<4; ++i) {int xx=x+dx[i],yy=y+dy[i];if(xx<1||xx>n||yy<1||yy>m||!id[xx][yy]) continue;if(vis[xx][yy]||xx==bx&&yy==by) continue;vis[xx][yy]=1;q.push(Icefox(xx,yy));}}for(int i=0; i<4; ++i) {int x=bx+dx[i],y=by+dy[i];if(x<1||x>n||y<1||y>m||!vis[x][y]) continue;f[bx][by][i]=0;q.push(Icefox(bx,by,i));}while(!q.empty()) {int x=q.front().x,y=q.front().y,op=q.front().op;q.pop();if(x==tx&&y==ty) {printf("%d\n",f[x][y][op]);return 0;}int xx=x+dx[3-op],yy=y+dy[3-op];//移动箱子到(xx,yy) if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&id[xx][yy]&&f[xx][yy][op]==-1)f[xx][yy][op]=f[x][y][op]+1,q.push(Icefox(xx,yy,op));for(int i=0; i<4; ++i) {//移动人到另一个方向 if(f[x][y][i]!=-1) continue;xx=x+dx[i];yy=y+dy[i];if(!id[xx][yy]) continue;if(!jud(id[xx][yy],id[x+dx[op]][y+dy[op]],id[x][y])) continue;f[x][y][i]=f[x][y][op];q.push(Icefox(x,y,i));}}puts("NO");return 0;
}

改了一下,判断两点是否有第二个路径的时候,是这样判断的:已知人移动前的位置编号x,人移动后的位置编号y,箱子所在位置编号z,因为一个事实的存在:xyz三点一定是相邻的,并且z被夹在中间,也就是不会有x-y-z这种情况,那么看xy是否连通,可以分z的两种情况考虑:z如果是割点,那xy必须要属于一个bcc才return1;如果z不是割点,那么直接return 1就行(其实还是在一个bcc中),因为这时候要么xy都不是割点,也就是都属于一个bcc中(因为相邻的三个点都不是割点那么一定属于同一个bcc),要么x或者y其中一个是割点,此时割点也可以看成和z是在一个bcc中的,所以也可以归类上去。当然,似乎还有种特殊情况,就是一共就三个点,这时这三个点属于两个bcc,但是这种情况的话z一定是割点,属于我们分类的第一种情况而不是现在讨论的第二种,所以在第二种情况中不需要考虑。

代码如下:(不知道正确与否)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 110
inline int read() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x*f;
}
int n,m,Q,id[N][N],h[N*N],num=0,f[N][N][4],owo=0,sx,sy,bx,by,tx,ty;
int dx[]= {0,-1,1,0},dy[]= {-1,0,0,1}; //0--往左推,1--上,2--下,3--右
char s[N];
bool vis[N][N];
int dfn[N*N],low[N*N],dfnum=0,bel[N*N],ofo=0,fa[N*N];
bool isge[N*N]; 
struct edge {int to,next;
} data[N*N*4];
struct Icefox {int x,y,op;Icefox(int _x,int _y,int _op=0) {x=_x;y=_y;op=_op;}
};
inline void add(int x,int y) {data[++num].to=y;data[num].next=h[x];h[x]=num;data[++num].to=x;data[num].next=h[y];h[y]=num;
}
stack<int>qq;
inline void tarjan(int x,int Fa) {dfn[x]=low[x]=++dfnum;qq.push(x);for(int i=h[x]; i; i=data[i].next) {int y=data[i].to;if(y==Fa) continue;if(!dfn[y]) {tarjan(y,x);low[x]=min(low[x],low[y]);if(low[y]<dfn[x]) continue;++ofo;fa[ofo]=x;isge[x]=1;while(1) {int z=qq.top();qq.pop();bel[z]=ofo;if(z==y) break;}continue;}low[x]=min(low[x],dfn[y]);}
}
inline bool jud(int x,int y,int z) {if(isge[z]==1) return bel[x]==bel[y];else return 1;
}
int main() {n=read();m=read();for(int i=1; i<=n; ++i) {scanf("%s",s+1);for(int j=1; j<=m; ++j) {if(s[j]=='S') continue;id[i][j]=++owo;if(s[j]=='M') sx=i,sy=j;if(s[j]=='P') bx=i,by=j;if(s[j]=='K') tx=i,ty=j;for(int k=0; k<2; ++k) {int x=i+dx[k],y=j+dy[k];if(x<1||x>n||y<1||y>m||!id[x][y]) continue;add(id[i][j],id[x][y]);//直接就是加双向边 }}}for(int i=1; i<=owo; ++i) if(!dfn[i]) tarjan(i,0);memset(f,-1,sizeof(f));queue<Icefox>q;q.push(Icefox(sx,sy));vis[sx][sy]=1;while(!q.empty()) {int x=q.front().x,y=q.front().y;q.pop();for(int i=0; i<4; ++i) {int xx=x+dx[i],yy=y+dy[i];if(xx<1||xx>n||yy<1||yy>m||!id[xx][yy]) continue;if(vis[xx][yy]||xx==bx&&yy==by) continue;vis[xx][yy]=1;q.push(Icefox(xx,yy));}}for(int i=0; i<4; ++i) {int x=bx+dx[i],y=by+dy[i];if(x<1||x>n||y<1||y>m||!vis[x][y]) continue;f[bx][by][i]=0;q.push(Icefox(bx,by,i));}while(!q.empty()) {int x=q.front().x,y=q.front().y,op=q.front().op;q.pop();if(x==tx&&y==ty) {printf("%d\n",f[x][y][op]);return 0;}int xx=x+dx[3-op],yy=y+dy[3-op];//移动箱子到(xx,yy) if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&id[xx][yy]&&f[xx][yy][op]==-1)f[xx][yy][op]=f[x][y][op]+1,q.push(Icefox(xx,yy,op));for(int i=0; i<4; ++i) {//移动人到另一个方向 if(f[x][y][i]!=-1) continue;xx=x+dx[i];yy=y+dy[i];if(!id[xx][yy]) continue;if(!jud(id[xx][yy],id[x+dx[op]][y+dy[op]],id[x][y])) continue;f[x][y][i]=f[x][y][op];q.push(Icefox(x,y,i));}}puts("NO");return 0;
}

 

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

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

相关文章

机器学习笔记(3):线性代数回顾

目录 1&#xff09;Matrices and vectors 2&#xff09;Addition and scalar multiplication 3&#xff09;Matrix-vector multiplication 4&#xff09;Matrix-matrix multiplication 5&#xff09;Matrix multiplication properties 6&#xff09;Inverse and transpos…

hadoop 安装

Hadoop单机和伪分布式安装 更新apt 用root用户登录 先更新一下 apt apt-get update然后安装vim apt-get install vim安装VMware tools tools 安装 安装SSH、配置SSH无密码登陆 单节点模式都需要用到 SSH 登陆&#xff0c;Ubuntu 默认已安装了 SSH client&#xff0c;此…

机器学习笔记(4):多变量线性回归

目录 1&#xff09;Multiple Features 2&#xff09;Gradient descent for multiple variables 3&#xff09;Gradient descent in practice 1: Feature Scaling 4&#xff09;Gradient descent in pratice2: Learning rate 5&#xff09;Features and polynomial regress…

【POJ - 2942】Knights of the Round Table(点双连通分量,二分图判断奇环奇圈)

题干&#xff1a; Being a knight is a very attractive career: searching for the Holy Grail, saving damsels in distress, and drinking with the other knights are fun things to do. Therefore, it is not very surprising that in recent years the kingdom of King …

zookeeper单节点部署

hadoop 安装 在/install-package目录下查看zookeeper的安装包 本文中安装的是zookeeper-3.4.12.tar.gz 下方为百度云链接 链接&#xff1a;https://pan.baidu.com/s/1bzq4ILH41owtS__3tBCcRQ 提取码&#xff1a;6q4r 把下载好的zookeeper-3.4.12.tar.gz 放到/install-packa…

机器学习笔记(五):逻辑回归

目录 1&#xff09;Classification 2&#xff09;Hypothesis Representation 3&#xff09;Decision boundary 4&#xff09;Cost function 5&#xff09;Simplified cost function and gradient descent 6&#xff09;Multi-class classification:One-vs-all 7&#xf…

xrdp完美实现Windows远程访问Ubuntu 16.04

前言&#xff1a; 在很多场景下&#xff0c;我们需要远程连接到Linux服务器(本文是Ubuntu)&#xff0c;传统的连接主要分为两种。 第一种&#xff1a;通过SSH服务&#xff08;使用xshell等工具&#xff09;来远程访问&#xff0c;编写终端命令&#xff0c;不过这个是无界面的&a…

【HDU - 6203】ping ping ping(lca+贪心思想,对lca排序,树状数组差分)

题干&#xff1a; 给出一个n1个点的树&#xff0c;以及p个点对&#xff0c;需要断开一些点&#xff0c;使得这p个点对路径不连通。输出应该断开的最少点数。 解题报告&#xff1a; 从那p个点对入手的话&#xff1a;首先考虑只有一对点的话&#xff0c;肯定是这条路径上的随便…

机器学习笔记(六):正则化

目录 1&#xff09;The problem of overfitting 2&#xff09;Cost function 3&#xff09;Regularized linear regression 4&#xff09;Regularized logistic regression 我们已经学习了线性回归和逻辑回归算法&#xff0c;已经可以有效解决很多问题&#xff0c;但是在实…

Hbase单节点安装

zookeeper单节点部署 实验环境 操作系统&#xff1a;Ubuntu 16.04 Hadoop&#xff1a;Hadoop 2.7.5 Zookeeper&#xff1a;zookeeper 3.4.12 Java&#xff1a;java version 1.8.0 到/install-package目录下查看hbase安装包 #>ls /install-package本文中用的是hbase-1…

ROS 常用命令字典

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请标明出处: http://www.cnblogs.com/liu-fa/p/5761448.html 该博文适合已经具备一定的ROS编程基础的人&#xff0c;快速查看ROS相关指令。 本文持续更新中&#xff0c;望关注收藏&#xff0c;一起改进... 创建 ROS 工作…

【HDU - 3966】Aragorn's Story(树链剖分,模板题)

题干&#xff1a; Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who want to invade his kingdom. As Aragorn knows, the enemy has N camps out of his kingdom and M edges connect t…

机器学习笔记(七):神经网络:表示

目录 1&#xff09;Non-linear hypotheses 2&#xff09;Model representation 1 3&#xff09;Model representation 2 4&#xff09;Examples and intuitions 1 5&#xff09;Examples and intuitions 2 6&#xff09;Multi-class classification 1&#xff09;Non-lin…

ROS入门_1.10 理解ROS服务和参数

目录 ROS Services使用rosservice rosservice listrosservice typerosservice call Using rosparam rosparam listrosparam set and rosparam getrosparam dump and rosparam load 本教程假设从前一教程启动的turtlesim_node仍在运行&#xff0c;现在我们来看看turtlesim提供了…

1.Introduction and Evaluation

感谢七月在线罗老师和吴同学&#xff01; 最近报了七月在线的《推荐系统实战》班&#xff0c;根据上课资料和思维导图整理了这篇笔记&#xff01; 1&#xff09;推荐系统介绍 思维导图如下&#xff0c;其中需要掌握的是推荐系统存在的前提&#xff1a;信息过载和用户需求不明…

【ZOJ - 2968 】Difference Game (贪心,思维模拟)

题干&#xff1a; Now you are going to play an interesting game. In this game, you are given two groups of distinct integers and C coins. The two groups, named Ga and Gbrespectively, are not empty and contain the same number of integers at first. Each time…

使用 rqt_console 和 roslaunch

Description:本教程介绍如何使用 rqt_console 和 rqt_logger_level 进行调试&#xff0c;以及如何使用 roslaunch 同时运行多个节点。早期版本中的 rqt 工具并不完善&#xff0c;因此&#xff0c;如果你使用的是“ROS fuerte”或更早期的版本&#xff0c;请同时参考 这个页面 学…

机器学习必备宝典-《统计学习方法》的python代码实现、电子书及课件

本文转自微信公众号&#xff1a;机器学习初学者 原创&#xff1a; 机器学习初学者 机器学习初学者 6天前 《统计学习方法》可以说是机器学习的入门宝典&#xff0c;许多机器学习培训班、互联网企业的面试、笔试题目&#xff0c;很多都参考这本书。本站根据网上资料用python复现…

【2019牛客暑期多校训练营(第一场) - H】XOR(线性基,期望的线性性)

题干&#xff1a; 链接&#xff1a;https://ac.nowcoder.com/acm/contest/881/H 来源&#xff1a;牛客网 Bobo has a set A of n integers a1,a2,…,ana1,a2,…,an. He wants to know the sum of sizes for all subsets of A whose xor sum is zero modulo (1097)(1097). F…

机器学习入门必备的13张“小抄”(附下载)

目录 1&#xff09;TensorFlow 2&#xff09;Keras 3&#xff09;Neural Networks 4&#xff09;Numpy 5&#xff09;Scipy 6&#xff09;Pandas 7&#xff09;Scikit-learn 8&#xff09;Matplotlib 9&#xff09;PythonForDataScience 最近在github上发现了很有用的…