BUPT Summer Journey #test6 E

 

E. 萌学妹的手机 2014新生暑假个人排位赛06

时间限制 1000 ms     内存限制 65536 KB    

题目描述

    学妹的手机马上就要没电了!

    手机网络是由蜂窝基站提供的,手机会自动搜寻最近的一个基站连接信号。每个基站的范围为一个正六边形。作为北邮的萌妹子当然知道切换基站是很费电的,所以要尽量不切换基站。学妹有一张地图在手中,想让你帮忙规划一下线路,让自己的手机尽可能少的切换基站。
    学妹的出发地和目的地均为平面直角坐标系上的点,为了方便计算,我们假设在坐标原点处有一个基站,基站范围的正六边形以基站为几何中心。
    六边形的边长为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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值