#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 */