题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5550
求 i 到 j 的最短距离
坐标系建立: y轴正常建,x轴分成两部分,x<0时x轴平行于5->3的方向,x>0时x轴平行于3->11的方向
原来每一层是这样
12 13 14 15 16 17 18 19 20
05 06 07 08 09 10 11
02 03 04
01 (第一层)
我们发现当层数 i 为奇数时,num【i】= num【i-1】+4,偶数时num【i】= num【i-1】+2
按正常坐标轴展开后是这样
89 68 50 35 23 24 25 26 27 28 29 30 31 47 66 88 113
49 34 22 13 14 15 16 17 18 19 32 48 67
21 12 06 07 08 09 1020 33
05 02 03 04 11
01 (第一层)
第 i 层两端各有(i-1)/2个元素的位置改变
这样每一个数的坐标就都可以得到了
接下来求两个点(x,y)和(xx,yy)之间的距离
当x<=0时,(x,y)到(x+1,y-1)只需要一步
当 x>0 时,(x,y)到 (x-1,y-1)只需要一步
其他的改变需要fabs(x-xx)+fabs(y-yy)步
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <queue>
#include <vector>
#include <math.h>
#include <stack>
#include <map>
#include <set>
#define rtl rt<<1
#define rtr rt<<1|1
typedef long long LL;
using namespace std;
const int mod = 1e9+7;
const int MAX = 1e6+10;
const double eps = 1e-10;
const double PI = acos(-1.0);
int x, y, xx, yy, a, b, ans;
struct node
{
int l, r, mid, p;
} lxt[100];
void f(int n, int &x, int &y)
{
if(n==1)
{
x = 0;
y = 1;
}
else
{
int k;
for(k = 2; k<=82; ++k)
if(lxt[k].l<=n&&lxt[k].r>=n)break;
y = k;
if(n<lxt[k].l+lxt[k].p)
{
y-=lxt[k].l+lxt[k].p-n;
x = lxt[k].l-lxt[k].mid+lxt[k].p;
}
else if(n>lxt[k].r-lxt[k].p)
{
y-= n-lxt[k].r+lxt[k].p;
x = lxt[k].r-lxt[k].mid-lxt[k].p;
}
else x = n-lxt[k].mid;
}
}
void dis()
{
if(x>xx)
{
swap(x, xx);
swap(y, yy);
}
while(x<xx&&y<yy)
{
if(xx<=0)ans+=2;
else ans+=1;
yy--;
xx--;
}
while(x<xx&&y>yy)
{
x++;
y--;
if(x<=0)ans+=1;
else ans+=2;
}
ans+=fabs(yy-y)+xx-x;
}
int main()
{
lxt[1].l = lxt[1].r=lxt[1].mid = 1;
lxt[1].p = 0;
for(int i = 2; i<=82; ++i)
{
lxt[i].l = lxt[i-1].r+1;
lxt[i].r = lxt[i].l+lxt[i-1].r-lxt[i-1].l+(2<<(i&1));
lxt[i].mid = (lxt[i].l+lxt[i].r)>>1;
lxt[i].p = max(0, (i-1)/2);
}
while(~scanf("%d%d", &a, &b))
{
if(!a&&!b)break;
f(a, x, y);
f(b, xx, yy);
ans = 0;
dis();
cout<<ans<<endl;
}
return 0;
}