Beehive UVALive - 7528 (找规律+数学思维)

点击打开链接

There is an infinite beehive like the one given in the figure. We consider two cells to be adjacent if andonly if they share a side. A path of length k from cell c0 to cell ck is a sequence of cells c0, c1, . . . , cksuch that ci and ci+1 are adjacent for all 0 ≤ i < k. The distance between cells i and j is the length ofthe shortest path from cell i to cell j

这里写图片描述

The cells of the beehive are indexed using positive integers as shown. The cells with larger distancefrom cell 1 are given larger indices. The indices of cells with the same distance from cell 1 increasesfrom left to right. Each positive integer is the index of exactly one cell.We want to know the distance of two cells whose indices are given.

Input

There are multiple test cases in the input. Each test case is a single line containing two space-separatedintegers i and j as the indices of two cells (1 ≤ i, j ≤ 104). The input terminates with a line containing‘0 0’ which should not be processed as a test case.

output

For each test case, output a single line containing the distance of the given cells.

Sample Input

8 4

11 12

365 365

0 0

Sample Output

2

5

0

Ps:皇天不负有心人,调试了两天的程序终于ac出来了

题目大意:

在如上图所示的规律去摆放数字,求任意两个数字之间的最小距离

题解:首先根据这个图求出每个数的横纵坐标,可以发现是一圈一圈的摆放的,对于第一圈(也就是1),第二圈和第一圈相同,都是先在最左边的一列上放一个数,然后在往右放,到最右边的一列的时候在放一个,对于第2,3圈,可以看出是在最左边和最右边的列放两个,一次类推出其他数字的摆放过程,根据这个过程求出每个数字的坐标。

定义在一列上的两个相邻的数字相差2,斜着相邻的数字相差1

当两个数字在同一列上时dx==0,其最短距离就是dy/2,(除以2是因为我记录坐标是相差2),在同一行上时,最短距离就是dx.(特殊考虑)

如果dx=0,或者dy=0,或者两个格子在同一斜排(dx=dy),直接算即可dis=max(dx,dy)。 
可以看出来,任意不在一排的两个点都是可以看做一个平行四边形的对角顶点,而最近的走法就是在整个平行四边形内部走,而且,只要是在内部,不走回头路的话,走的距离都是一样的。 
所以,对于dx>dy的情况,距离dis=dx 
对于dy>dx的情况,dis=dx+(dy-dx)/2

#include <bits/stdc++.h>

using namespace std;
struct node
{
    int lie;
    int hang;
} vis[211111];

int d[211111];///记录每一列的当时高度(即hang )
int main()
{
    memset(vis,0,sizeof(vis));
    memset(d,0,sizeof(d));
    ///初始化前两圈
    int n,m;
    vis[1].lie=100000;
    vis[1].hang=1;
    d[10000]=1;
    vis[2].lie=99999;
    vis[2].hang=2;
    d[99999]=2;
    vis[3].lie=100000;
    vis[3].hang=3;
    d[100000]=3;
    vis[4].lie=100001;
    vis[4].hang=2;
    d[100001]=2;
    int cnt=5;
    int ans=2;
    int l=99998,r=100002;
    while(1)
    {
        ///求出每个数字的坐标
        if(cnt>111111)break;
        for(int j=1; j>=0; j--)///每两圈最左边的数字高度加1
        {
            if(j==1)d[l]=-1;///数字高度(从1开始)
            else d[l]=0;///(从0开始)
            for(int i=0; i<ans; i++)///数字高度为ans加在最左列
            {
//                if(cnt==14)
//                {
//                    cout<<"lie="<<i<<endl;
//                    cout<<ans<<endl;
//                }
                d[l]+=2;
                vis[cnt].hang=d[l];
                vis[cnt++].lie=l;
            }
            for(int i=l+1; i<r; i++)
            {
//                if(cnt==14)
//                {
//                    cout<<"lie="<<i<<endl;
//                }
                d[i]+=2;
                vis[cnt].hang=d[i];
                vis[cnt++].lie=i;
            }
            int k;
            if(j)k=ans*2-1;///每次上升2
            else k=ans*2;
            for(int i=0; i<ans; i++)///数字高度为ans加在最右列
            {
//                if(cnt==66)
//                {
//                    cout<<ans*2-1<<endl;
//                    cout<<k<<endl;
//                    cout<<ans<<endl;
//                }
                vis[cnt].hang=k;
                vis[cnt++].lie=r;
                k=k-2;
            }
            if(j)d[r]=ans*2-1;
            else d[r]=ans*2;
            l--;
            r++;
        }
        ans++;
    }
    //for(int i=1; i<=100; i++)printf("%d %d %d\n",i,vis[i].hang,vis[i].lie);
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)break;
        int dx=abs(vis[n].lie-vis[m].lie);
        int dy=abs(vis[n].hang-vis[m].hang);
        if(dx==0)printf("%d\n",dy/2);
        else if(dy==0||dx==dy)printf("%d\n",max(dx,dy));
        else
        {
            if(dx>dy)printf("%d\n",dx);
            else printf("%d\n",dx+(dy-dx)/2);
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值