E. 萌学妹的手机 2014新生暑假个人排位赛06
题目描述
学妹的手机马上就要没电了!
手机网络是由蜂窝基站提供的,手机会自动搜寻最近的一个基站连接信号。每个基站的范围为一个正六边形。作为北邮的萌妹子当然知道切换基站是很费电的,所以要尽量不切换基站。学妹有一张地图在手中,想让你帮忙规划一下线路,让自己的手机尽可能少的切换基站。
学妹的出发地和目的地均为平面直角坐标系上的点,为了方便计算,我们假设在坐标原点处有一个基站,基站范围的正六边形以基站为几何中心。
六边形的边长为L,我们假设整个平面都有信号。小学妹很聪明,所以不会在基站间的边缘行走,也不会在三个基站区域相交的顶点停留,因为这样都会让手机付出非常大的耗电代价。
学妹希望知道她最少需要穿越多少次边界才能够到达目的地。(六边形的方向为有两条边平行于y轴,有两个顶点分别朝北朝南)
输入格式
第一行为数据组数,整数T (T<=1000)
每组数据格式如下:
第一行 : 基站范围的正六边形边长,正实数 L ( 0.1 <= L <= 10.0 )
第二行 : 出发点坐标,两个实数Sx Sy (-150000.0 <= Sx, Sy <= 150000.0)
第三行 : 目标点坐标,两个实数Dx Dy (-150000.0 <= Dx, Dy <= 150000.0)
输出格式
每组数据输出一行,为一个整数,表示小胖最少需要穿越的基站范围边缘的次数。
数据保证起始点终点不会在六边形边缘上。
输入样例
2
2.0
0 0
6 -1
2.0
0 0
9 -1
输出样例
2
3
思路: 首先,对于人而言,要穿过最少,肯定要在同一块里往目标方向尽量走,实在不行了再跳到最接近的格子。我们可以先把六边形划分成一个个矩形,根据矩形进行参考,然后将坐标系按照y=+-sqrt(3)x划分成四个区域。若处在上下两个区域,则直接走。若处在左右两个区域,则先斜着走后再横过去。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define eps 1e-7
#define LOCAL
using namespace std;
struct Point
{
double x,y;
}r,s,t,st,ed;
double L;
void Init()
{
L=sqrt(3)*L;
//l=sqrt(3)*l/2;
if(s.x>0)r.x=((int)(s.x/L+eps))*L;
else r.x=((int)(s.x/L-eps)-1)*L;
if(s.y>0)r.y=((int)(s.y/(sqrt(3)*L)+eps))*L*sqrt(3);
else r.y=((int)(s.y/(sqrt(3)*L)-eps)-1)*L*sqrt(3);
//printf("s.x=%lf s.y=%lf t.x=%lf t.y=%lf r.x=%lf r.y=%lf\n",s.x,s.y,t.x,t.y,r.x,r.y);
//printf("yes%lf\n",s.y-r.y-L/sqrt(3)+(s.x-r.x)/sqrt(3));
if(s.x<r.x+L/2)
{
if(s.y-r.y-L/sqrt(3)+(s.x-r.x)/sqrt(3)<0){st.x=r.x;st.y=r.y;}
else if(s.y-r.y-2*L/sqrt(3)-(s.x-r.x)/sqrt(3)>0){st.x=r.x;st.y=r.y+L*sqrt(3);}
else {st.x=r.x+L/2;st.y=r.y+sqrt(3)*L/2;}
}
else
{
if(s.y-r.y-L/sqrt(3)-(s.x-r.x-L)/sqrt(3)<0){st.x=r.x+L;st.y=r.y;}
else if(s.y-r.y-2*L/sqrt(3)+(s.x-r.x-L)/sqrt(3)>0){st.x=r.x+L;st.y=r.y+L*sqrt(3);}
else {st.x=r.x+L/2;st.y=r.y+sqrt(3)*L/2;}
}
//printf("st.x=%lf st.y=%lf\n",st.x,st.y);
if(t.x>0)r.x=(int)(t.x/L+eps)*L;
else r.x=(int)(t.x/L+eps-1)*L;
if(t.y>0)r.y=(int)(t.y/(sqrt(3)*L)+eps)*L*sqrt(3);
else r.y=(int)(t.y/(sqrt(3)*L)+eps-1)*L*sqrt(3);
if(t.x<r.x+L/2)
{
if(t.y-r.y-L/sqrt(3)+(t.x-r.x)/sqrt(3)<0){ed.x=r.x;ed.y=r.y;}
else if(t.y-r.y-2*L/sqrt(3)-(t.x-r.x)/sqrt(3)>0){ed.x=r.x;ed.y=r.y+L*sqrt(3);}
else {ed.x=r.x+L/2;ed.y=r.y+sqrt(3)*L/2;}
}
else
{
if(t.y-r.y-L/sqrt(3)-(t.x-r.x-L)/sqrt(3)<0){ed.x=r.x+L;ed.y=r.y;}
else if(t.y-r.y-2*L/sqrt(3)+(t.x-r.x-L)/sqrt(3)>0){ed.x=r.x+L;ed.y=r.y+L*sqrt(3);}
else {ed.x=r.x+L/2;ed.y=r.y+sqrt(3)*L/2;}
}
//printf("st.x=%lf st.y=%lf ed.x=%lf ed.y=%lf\n",st.x,st.y,ed.x,ed.y);
//printf("s.x=%lf s.y=%lf t.x=%lf t.y=%lf r.x=%lf r.y=%lf\n",s.x,s.y,t.x,t.y,r.x,r.y);
}
void Solve()
{
if(((ed.y-st.y)-sqrt(3)*(ed.x-st.x))*((ed.y-st.y)+sqrt(3)*(ed.x-st.x))>0)printf("%d\n",(int)(abs(ed.y-st.y)/(sqrt(3)*L/2)+eps));
else
{
int ansy=(int)(abs(ed.y-st.y)/(sqrt(3)*L/2)+eps);//printf("ansy=%d\n",ansy);//printf("%lf\n",abs(ed.y-st.y));
int ansx=(int)((abs(ed.x-st.x)-ansy*L/2)/L+eps);//printf("ansx=%d\n",ansx);
//printf("%lf\n",abs(ed.x-st.x));
printf("%d\n",ansx+ansy);
}
}
int main()
{
#ifdef LOCAL
//freopen("input.txt","r",stdin);
//freopen("E.txt","w",stdout);
#endif // LOCAL
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lf%lf%lf%lf%lf",&L,&s.x,&s.y,&t.x,&t.y);
Init();
Solve();
}
return 0;
}