#include<stdio.h>
#include<iostream>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<string>
#include<algorithm>
#include<time.h>
#include<bitset>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T> inline void gmax(T &a,T b){if(b>a)a=b;}
template <class T> inline void gmin(T &a,T b){if(b<a)a=b;}
const int N=0,M=0,Z=1e9+7,maxint=2147483647,ms31=522133279,ms63=1061109567,ms127=2139062143;const double eps=1e-8,PI=acos(-1.0);//.0
int casenum,casei;
char a[64][64];
bool e[120][64][64];//用e[u][i][j]表示在时刻为u时,位置(i,j)的安全性
int n,m,p,g;
int sty,stx,edy,edx;
int h,t;
struct B{int y,x;}b[205][120];//用b[i][j]表示第i个保安在循环节定位为j时的位置
const int dy[4]={-1,0,0,1};
const int dx[4]={0,-1,1,0};
const int L=3600*125;
int qu[L],qy[L],qx[L];
void dfs(int u,int y,int x)
{
e[u][y][x]=0;
for(int i=0;i<4;i++)
{
int yy=y;
int xx=x;
while(1)
{
yy+=dy[i];
xx+=dx[i];
if(a[yy][xx]!='.')break;
e[u][yy][xx]=0;
}
}
}
bool inq(int u,int y,int x)
{
int uu=u%120;
if(y==edy&&x==edx)return 1;
if(!e[uu][y][x])return 0;
e[uu][y][x]=0;
qu[t]=u;
qy[t]=y;
qx[t++]=x;
return 0;
}
int bfs()
{
h=t=0;
inq(0,sty,stx);
while(h<t)
{
int u=qu[h]+1;
int y=qy[h];
int x=qx[h++];
for(int i=0;i<4;i++)
{
if(inq(u,y+dy[i],x+dx[i]))return u;
}
if(inq(u,y,x))return u;
}
return -1;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
MS(a,0);
MS(e,0);
//scanf(" (%d%d)",&sty,&stx);
//scanf(" (%d%d)",&edy,&edx);
scanf("%*[^0-9]%d%d)",&sty,&stx);
scanf("%*[^0-9]%d%d)",&edy,&edx);
for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
for(int u=0;u<120;u++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
e[u][i][j]=a[i][j]=='.';
}
}
}
scanf("%d",&p);
for(int i=1;i<=p;i++)
{
scanf("%d",&g);
for(int j=0;j<g;j++)scanf(" (%d%d)",&b[i][j].y,&b[i][j].x);
int G=g+g-2;
for(int j=g;j<G;j++)b[i][j]=b[i][G-j];
if(G==0)for(int j=1;j<120;j++)b[i][j]=b[i][0];
else for(int j=G;j<120;j++)b[i][j]=b[i][j%G];
}
for(int i=0;i<120;i++)
{
for(int j=1;j<=p;j++)
{
int y=b[j][i].y;
int x=b[j][i].x;
dfs(i,y,x);
}
}
int ans=bfs();
if(ans==-1)puts("IMPOSSIBLE");
else printf("%d\n",ans);
}
return 0;
}
/*
【trick&&吐槽】
1,scanf可以实现很多神奇的功能。
比如:scanf(" %c")可以先吃掉所有换行和空格,然后读入第一个可见字符
比如:scanf("(%d,%d")可以实现读入类似于"(1,2)"这样格式的数
这道题比赛时没能实现第二个功能,是因为'('之前有空格,我们只要改成scanf(" (%d%d)",&y,&x))就可以了
再不要忘记了——
比如:scanf("%[0-9])就是只读入数字,遇到不是数字终止
比如:scanf("%[^0-9]就是只读入非数字,遇到数字终止
即这题也可以写成scanf("%*[^0-9]%d%d)",&sty,&stx);
2,除法一定要提防除0
【题意】
给你一个n(60)*m(60)的迷宫,格子是'.'表示为可行,是'#'表示为障碍物。
我们一开始在(sty,stx),最后想要到达(edy,edx)。
每次可以上下左右走一步,或者呆在原地静止不动。
然而地图上有p([1,200])个人在巡逻,每个人巡逻的路线是一条长度为[1,g]的相邻格点段,一旦走到格点段的端点1或g,就往回走。
如果在同一时刻,我们与任何一个巡逻者位于同一行或同一列,且两者之间没有任何障碍物,那么我们就会被逮到,就失败。
特别的一点是,如果我们在刚刚到达edy,edx时刻被抓到,那么也同样认定为successful
现在问你,最少的使得我们到达(edy,edx)的步数。
如果无法successful,输出-1
【类型】
迷宫搜索
【分析】
首先这道题,因为巡逻的路线长度为g=[1,7],所以我们可以把其映射得到一整个循环长度G=g*2-2,
也就是说,每经过G步,某个巡逻者的状态是相同的。
巡逻长度[1,7]所对应的巡逻长度,分别是[0,2,4,6,8,10,12]
这些数的最小公倍数是120,也就是说,每过120步,所有保安的位置都与之前对应相同。
于是,我们一开始可以做预处理。
得到,当现在的时刻为t时的所有保安的位置,并进而得到地图上每个点是否安全。
然后,这个人就可以直接做三位状态的bfs(步数,纵坐标,横坐标)。
然后第一次达到的(edy,edx)的步数就是最后的答案。
还有一个细节,就是我们可以在到达(edy,edx)的同时被抓获。
这个可以通过调整入队的判定次序来实现。
1st,是否之前走过,走过就return
2nd,是否到达终点,到达就yes
3rd,是否安全,不安全就return
这道题就这么做完了
【时间复杂度&&优化】
预处理的复杂度是O(p*120*60),也不过是1.44e6
bfs的复杂度是O(n*m*120),也不过是3600*120不超过5e5。
所以这题可以顺利AC
【数据】
input
5 5
(2 5) (5 3)
.....
.#.#.
.#.#.
....#
.#.##
1
6 (4 2) (4 3) (3 3) (2 3) (1 3) (1 2)
output
26
input
5 4
(1 4) (5 4)
....
..#.
###.
....
###.
2
2 (2 2) (2 1)
4 (4 1) (4 2) (4 3) (4 3)
output
-1
input(小心除零)
5 5
(2 5) (5 3)
.....
.#.#.
.#.#.
....#
.#.##
1
1 (3 1)
output
*/
【UKIEPC2015 J】【趣味迷宫搜索】Jelly Raid 来回巡逻 不被发觉 循环节预处理
最新推荐文章于 2024-07-13 13:36:16 发布