题目描述:
frog is trapped in a maze. The maze is infinitely large and divided into grids. It also consists of n obstacles, where the i-th obstacle lies in grid (xi,yi).
frog is initially in grid (0,0), heading grid (1,0). She moves according to The Law of Right Turn: she keeps moving forward, and turns right encountering a obstacle.
The maze is so large that frog has no chance to escape. Help her find out the number of turns she will make.
输入描述:
The input consists of multiple tests. For each test:
The first line contains 1 integer n (0≤n≤103). Each of the following n lines contains 2 integers xi,yi. (|xi|,|yi|≤109,(xi,yi)≠(0,0), all (xi,yi) are distinct)
输出描述:
For each test, write 1 integer which denotes the number of turns, or ``-1’’ if she makes infinite turns.
输入样例:
2
1 0
0 -1
1
0 1
4
1 0
0 1
0 -1
-1 0
输出样例:
2
0
-1
核心思想:
对于每一个障碍块,可以从四个方向撞击,每个方向撞击后都是右转,所以当撞击方向确定,被撞击的障碍块也确定时,下一步的方向是确定的。因此,我们可以根据规则将障碍块连接起来。每个障碍块最多有四个后继障碍块,根据相对位置,分别命名为shang,xia,zuo,you。将障碍块的二维坐标以及四个后继障碍块的下标封装成结构体。最后,根据撞击规则,模拟路径。
细节见代码。
代码如下:
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N=1e3+10;
struct node
{
int shang,xia,zuo,you;
int x,y;
} h[N];
bool vis[N][4];//将出现过的状态标记,如果状态重复出现,则输出-1
int b[4]= {1,2,3,0};//用于方向更新
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
memset(vis,0,sizeof(vis));
for(int i=1; i<=n; i++)
scanf("%d%d",&h[i].x,&h[i].y);
for(int i=1; i<=n; i++)
{
int ts=0,ty=0,tx=0,tz=0;//第i个障碍块的,上方、右侧、下方、左侧障碍块,为0则表示不存在
int a=inf,b=inf,c=-inf,d=-inf;//后继障碍块相应的x坐标或y坐标
for(int j=1; j<=n; j++)
{
if(h[j].x==h[i].x+1&&h[j].y>h[i].y&&h[j].y<a)//更近的上方障碍块出现
{
ts=j;
a=h[j].y;
}
else if(h[j].y==h[i].y-1&&h[j].x>h[i].x&&h[j].x<b)//更近的右侧障碍块出现
{
ty=j;
b=h[j].x;
}
else if(h[j].x==h[i].x-1&&h[j].y<h[i].y&&h[j].y>c)//更近的下方障碍块出现
{
tx=j;
c=h[j].y;
}
else if(h[j].y==h[i].y+1&&h[j].x<h[i].x&&h[j].x>d)//更近的左侧障碍块出现
{
tz=j;
d=h[j].x;
}
}
h[i].shang=ts;//更新第i个结构体的四个后继
h[i].you=ty;
h[i].xia=tx;
h[i].zuo=tz;
}
int st=0,tt=inf;
for(int i=1; i<=n; i++)//暴力找到第一个撞击的障碍块,作为起点
{
if(h[i].y==0&&h[i].x>0&&h[i].x<tt)
{
st=i;
tt=h[i].x;
}
}
if(st==0)//没找到第一个撞击的障碍块,一次转弯都没有,输出0
{
printf("0\n");
continue;
}
vis[st][0]=1;
int ans=0,k=st,f=0,flag=0;
while(1)
{
ans++;//右转一次
if(f==0)//撞击下一个障碍块
k=h[k].xia;
else if(f==1)
k=h[k].zuo;
else if(f==2)
k=h[k].shang;
else
k=h[k].you;
f=b[f];//更新方向
if(k==0)//找不到下一个障碍块,可以输出了
break;
if(vis[k][f])//状态重复,输出-1
{
flag=1;
printf("-1\n");
break;
}
vis[k][f]=1;//出现过的状态标记一下
}
if(flag)//已经输出-1,跳过下面的输出,避免重复输出
continue;
printf("%d\n",ans);
}
return 0;
}