第一步建立坐标系,以左下角第一个房子作为坐标原点(每个房子的编号统一-1,因为后面要用到%运算)
等级1的4个房子的坐标分别为
0(0,1) 1(1,1) 2(1,0) 3(0,0)
第二步根据给的等级n的城市的编号得到对应的坐标
等级为n的城市是由4个等级为n-1的城市拼接而成
左上是等级为n-1的城市顺时针旋转90度得到
左下角是等级为n-1的城市逆时针旋转90度得到
右上角和右下角就是原来的形状
从左上角开始顺时针依次为这4个n-1等级的城市编号为0 1 2 3
所以我们要求等级n的点的坐标,只要求出他是由等级n-1的城市哪一个坐标变化而来的即可
如何把等级n的点映射成等级n-1的点呢?
很明显只要对2^(2n - 2) 取模即可
因为是用等级n-1的4个城市拼接出来的,所以每个点一定可以映射成等级n-1的点
所以只要递归的调用get_location(n - 1 , id % 2^(2n-2)) 即可
得到等级n-1的坐标(x , y) (以左下角第一个房子作为坐标原点的坐标)
现在需要把这个坐标变化成等级n的坐标
我们需要知道给的编号是哪一个等级n-1的城市(有4个)
易知起点一定在左上角的城市中,终点在左下角的城市中
整体的路线是由左上角->右上角->右下角->左下角
所以我们只要对编号除于一个2^(2n-2) 即可
除的结果对应上面我们给4个等级n-1的编号即可找到属于哪一个了
第三步根据刚才得到的等级n-1的坐标(x,y)和对应的哪一个等级n-1的城市进行坐标变化
先在坐标原来的位置进行变化,再偏移到对应的区域
左下角:不需要偏移 原图形(注意是图形,不是坐标)进行逆时针旋转90度
先逆时针旋转90度(坐标旋转) 坐标变成(2^(n-1) - y - 1 , x)
再水平翻转,纵坐标不变
坐标变成 (2^(n-1)-(2^(n-1)-y-1)-1,x)==(y , x)
右上角:不需要旋转,只需要偏移
坐标变成 (x + 2^(n-1) , y + 2^(n-1))
右下角:不需要旋转,只需要偏移
坐标变成 (x + 2^(n-1) , y)
左上角:需要旋转 也需要偏移
先顺时针旋转90度 坐标变成了(y , 2^(n-1)-x-1)
再水平翻转 纵坐标不变
坐标变成 : (2^(n-1) - y - 1 , 2^(n-1) - x - 1)
最后再偏移到左上角
坐标变成: (2^(n-1) - y - 1 , 2^(n-1) - x - 1 + 2^(n-1))==(2^(n-1) - y - 1 , 2^n - x - 1)
第四步
得到2个坐标后用2点之间的距离公式得直线距离最后*10即可
坐标变换 在一个n * n的正方形中
坐标(x , y)顺时针旋转90度后的坐标为
(y , n - x)
逆时针旋转90度后的坐标为
(n - y , x)
旋转180度后的坐标为
(n - x , n - y)
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
void get_location(int n , LL id , LL & x ,LL & y){
if (n == 0){ //等级为1的城市也可以看成有4个n-1的城市拼成
x = 0 , y = 0;
return ;
}
//递归调用n-1
LL mod = 1ll << (2 * n - 2); //2^(2n-2)==2^2n / 4
LL add = 1ll << (n - 1);
get_location(n - 1 , id % mod , x , y);
//得到n-1的坐标后,把其变成等级n的装备
//先找到属于哪一个n-1的城市
LL z = id / mod;
if (z == 0){ //左上角 (2^(n-1) - y - 1 , 2^n - x - 1)
LL temp = x;
x = add - y - 1;
y = 2 * add - temp - 1;
}
else if (z == 1){ //右上角 (x + 2^(n-1) , y + 2^(n-1))
x += add;
y += add;
}
else if (z == 2){ //右下角 (x + 2^(n-1) , y)
x += add;
}
else{ //左下角 //(y , x)
swap(x , y);
}
}
LL rounding(double a) {
LL b;
if(a > 0) b = (a * 2 + 1) / 2;
else b = (a * 2 - 1) / 2;
return b;
}
int q;
int main (){
cin >> q;
while (q--){
int n = 0;
LL a = 0;
LL b = 0;
scanf ("%d %lld %lld" , &n , &a , &b);
LL A_x = 0;
LL A_y = 0;
LL B_x = 0;
LL B_y = 0;
get_location(n , a - 1 , A_x , A_y); //得到等级n城市a的坐标
//cout << A_x << " " << A_y << endl;
get_location(n , b - 1 , B_x , B_y); //得到等级n城市a的坐标
//利用2点之间的距离公式
LL x = B_x - A_x;
LL y = B_y - A_y;
double d = sqrt(y * y + x * x) * 10.00;
printf ("%.0lf\n" , d); //自动四舍五入
}
return 0;
}