POJ1376
原题链接https://vjudge.net/contest/350953#problem/G
一道bfs的题,计算从所给的起点到终点的时间,需要注意的是机器人的头的方向还要特别考虑 ,只能朝面朝的方向走,而且只能向左转90或者向右转90(也就是说每个情况可以延伸出三种情况,向前,向左转,向右转)同时转身也会消耗一次时间,机器人前进的步数有三种,向前1 2 3 步也就是三种情况
将情况理清之后便是建图,这题意有点难懂还是英文,而且有点小神奇(biantai?)
题目给出了9×10 的图但是这个图是真正的地图上的障碍物的分布形况,1个点代表真正地图四个点(4个点会有重叠部分,主要针对有障碍物(1*1的正方形会占4个点)的格子进行判断),唔,也就是说正式地图比给出的地图要横竖多一行,也就是10×11;
题目给的图就是样例的图,可以数一下格数,注意机器人走的是轨道,不是格子中间,而障碍物会将周围4个路(四条边)全部挡住,所以读取地图障碍物要注意,同时这是在一个商店里,(读题可以发现他提出了对于墙壁旁边的轨道的距离)也就是说,墙壁是不能走(比如(0,0)(0,1))的,也就是边界,只能沿着中间轨道走。(wa了14发的惨痛教训)
题意就是这样,细节有点多,又是英文题,所以本来其实算是基础的bfs题就显得有些困难。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <queue>
#include <stack>
using namespace std;
long long n, m;
long long map[100][100];//地图
long long vis[100][100][10];//多开数组记录来到这个点位的方向,不同方向到达这个点位也是不同的情况
long long mv[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};//移动的方向
struct node
{
long long x;//x轴
long long y;//y轴
long long t;//时间
long long z;//方向
} s, e;//s为记录起始状态,e记录结束状态
long long bfs()
{
queue<node> q;//建立队列记录数据
q.push(s);//放入起始数据
memset(vis, 0, sizeof(vis));
node s1, e1;//s1为当前数据变化前的数据,e1为经过变化之后的数据
long long i, j;
while (!q.empty())
{
s1 = q.front();
q.pop();
//printf("s=%lld %lld %lld %lld\n",s1.x,s1.y,s1.t,s1.z);
//if(s1.x==4&&s1.y==7&&s1.z==0)
// {
// printf("%lld",vis[e1.x][e1.y][e1.z]);
// printf("*******************\n");
// }
if (s1.x == e.x && s1.y == e.y)//结束条件,到达终点
{
return s1.t;
}
e1.x = s1.x;
e1.y = s1.y;
e1.t = s1.t + 1;//旋转一次时间要增加1,同时我们此时不进行这个方向的判断,要放入队列,以保证时间不会乱,
e1.z = (s1.z + 1) % 4;//+1根据之前设定的方向为向右旋转
// if(s1.x==4&&s1.y==7)
// {
// printf("%lld\n",vis[e1.x][e1.y][e1.z]);
// printf("%lld %lld %lld\n",e1.x,e1.y,e1.z);
// printf("*******************\n");
// }
if (vis[e1.x][e1.y][e1.z] == 0)//判断这个状态是否出现过
{
vis[e1.x][e1.y][e1.z] = 1;//标记
q.push(e1);
}
e1.x = s1.x;
e1.y = s1.y;
e1.t = s1.t + 1;//同上
e1.z = (s1.z-1+4) % 4;//想左旋转,+4以保证不会出现负数
// if(s1.x==4&&s1.y==7)
// {
// printf("%lld\n",vis[e1.x][e1.y][e1.z]);
// printf("%lld %lld %lld\n",e1.x,e1.y,e1.z);
// printf("*******************\n");
// }
if (vis[e1.x][e1.y][e1.z] == 0)
{
vis[e1.x][e1.y][e1.z] = 1;//标记
q.push(e1);
}
for (j = 1; j <= 3; j++)//判断不进行旋转向前进的情况,三种情况
{
e1.z = s1.z;
e1.t = s1.t;
e1.x = s1.x + mv[e1.z][0] * j;
e1.y = s1.y + mv[e1.z][1] * j;
// printf("%lld %lld****\n",mv[i][0]*j,mv[i][1]*j);
if (map[e1.x][e1.y] == 1)//如果走到障碍物就要跳出,因为只能沿轨道走,如果现在比如果1的位置出现障碍物,就不可能跳过障碍物去走两步或者三步,会不障碍物挡住而不能前进,所以后面的步数的情况也不需要考虑,直接跳出
{
break;
}
if (e1.x <= 0 || e1.y <= 0 || e1.x >= n || e1.y >= m || vis[e1.x][e1.y][e1.z] == 1)//出届或者情况出现过跳出,注意边界位置!!!!
{
continue;
}
e1.t++;//时间+1,标记放入队列
vis[e1.x][e1.y][e1.z] = 1;
q.push(e1);
}
}
return -1;//如果队列中所有情况跑完还没有到达终点,说明不能达到,输出-1;
}
int main()
{
long long i, j;
while (~scanf("%lld %lld", &n, &m))
{
if (n == 0 && m == 0)//如果数据为0 0 跳出
{
break;
}
long long t;
memset(map, 0, sizeof(map));
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
scanf("%lld", &t);//读取障碍物的状态,注意是障碍物,并不是直接是地图
if (t == 1)//将障碍物读入地图,至于为什么是这四个点,请将样例数据跟地图数据进行比较来确定。
{
map[i][j] = 1;
map[i + 1][j] = 1;
map[i][j + 1] = 1;
map[i + 1][j + 1] = 1;
}
}
}
scanf("%lld %lld %lld %lld", &s.x, &s.y, &e.x, &e.y);//读取起始位置和终止位置
// cout<<endl;
// map[s.x][s.y]=3;
// map[e.x][e.y]=3;
// for(i=0; i<n; i++)
// {
// for(j=0; j<m; j++)
// {
// printf("%lld ",map[i][j]);
// }
// cout<<endl;
// }
char ss[15];//读取方向,由于是英文用字符串读取
s.t = 0;
scanf("%s", ss);//四个方向的首字母不同,直接判断首字母就行
if (ss[0] == 'e')//对于每个方向的数字的代表要跟mv数组的方向对应,也就是说mv[s.z][0]以及mv[s.z][1]要刚好是朝这个方向移动。
{
s.z = 0;
}
else if (ss[0] == 's')
{
s.z = 1;
}
else if (ss[0] == 'w')
{
s.z = 2;
}
else if (ss[0] == 'n')
{
s.z = 3;
}
long long sum = bfs();//开始bfs
printf("%lld\n", sum);
}
return 0;
}