原题
https://codeforces.com/gym/101755/problem/H
题目大意
就是走迷宫,就是这么没新意,不同的是这次怪物也会动,而且还是瞬移的
S是起点,F是重点,M是怪物,. 就是普通地砖
从M开始d格都是危险区域,也就是不能走的地方
能从起点到终点输出要走的步数,不能则输出**-1**
题目分析
还是走迷宫,还是搜索,不过这次是求最短路径,所以就要用bfs了,第一个遇到的显然是答案
这条“没新意”的题的数据规模很奇葩,没错,2 ≤ n·m ≤ 200000,这是什么意思呢?大概就是说你的数组不能耿直的开到二维了,不然开个bool a[200000][200000]就等着MLE吧
卡了一天
解决方法就是开个一维数组,然后假装它是个二维数组,可以拿一个二重指针存每一行第一个数据的地址,而我就直接a[i][j] = *((a + i * n) + m)了
还有就是卡了一下时间,如果你在搜索怪物的时候把最后一步也入队了,就会在某个数据点TLE,我是在第44个点……
其它的小优化应该不是重点,只要上面那个剪枝做了应该就能过了。
代码
#include<cstdio>
#include<cstring>
int const dirx[4] = {0,1,0,-1};
int const diry[4] = {1,0,-1,0};//简化搜索
bool been[400010];//本质是二维数组
int fx[2000010],fy[2000010],dis[2000010],ft,fs;
int bx = -1,by = -1,ex = -1,ey = -1;
int n,m,d;
bool flag,f2 = false;
void place()
{
// f2 = true;
while (fs <= ft)
{
if ((fx[fs] == bx && fy[fs] == by) || (fx[fs] == ex && fy[fs] == ey))
{
flag = false;
return;
}
// *((been + fx[fs] * m) + fy[fs]) = true;
if (dis[fs] + 1 <= d)
for (int i = 0;i < 4;i++)
{
int nx = fx[fs] + dirx[i];
int ny = fy[fs] + diry[i];
if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
if (*((been + nx * m) + ny)) continue;
*((been + nx * m) + ny) = true;
if (dis[fs] <= d)
{
ft++;
fx[ft] = nx;fy[ft] = ny;dis[ft] = dis[fs] + 1;
}
}
fs++;
}
}
int walk()
{
fs = 0;ft = 0;
fx[ft] = bx;fy[ft] = by;dis[ft] = 0;
while (fs <= ft)
{
for (int i = 0;i < 4;i++)
{
int nx = fx[fs] + dirx[i];
int ny = fy[fs] + diry[i];
if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
if (*((been + nx * m) + ny)) continue;
if (nx == ex && ny == ey) return (dis[fs] + 1);
ft++;
fx[ft] = nx;fy[ft] = ny;dis[ft] = dis[fs] + 1;
*((been + fx[ft] * m) + fy[ft]) = true;
}
fs++;
}
return -1;
}
int main()
{
scanf("%d%d%d",&n,&m,&d);
getchar();
memset(been,0,sizeof(been));
fs = 0;ft = -1;flag = true;
for (int i = 0;i < n;i++)
{
for (int j = 0;j < m;j++)
switch (getchar())
{
case '.':
break;
case 'M':
ft++;fx[ft] = i;fy[ft] = j;dis[ft] = 0;
*((been + i * m) + j) = true;
// fs = 0;ft = -1;
break;
case 'S':
bx = i;by = j;
break;
case 'F':
ex = i;ey = j;
break;
default:
break;
}
getchar();
}
if (d >= n && d >= m && ft > 0) flag = false;
if (flag) place();
if(*((been + bx * m) + by) || *((been + ex * m) + ey)) flag = false;
memset(fx,0,sizeof(fx));
memset(fy,0,sizeof(fy));
memset(dis,0,sizeof(dis));
if (flag) printf("%d",walk());else printf("-1");
return 0;
}
反思
数学太差了啊……连数都不会计
i + 1 < d等价i <= d……鬼知道我当时是怎么想的