SCU-4445 Right turn 建图模拟

题目描述:

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值