分形之城.

在这里插入图片描述
从上图可以得出城市等级N和房屋数量的关系:
房屋数量=22N
要求两个城市之间的距离,我们就需要计算两个城市的坐标。每一座N级城市由4座N-1级城市组成,所以我们想要计算calc(N,M),M编号的房屋在N级城市的编号,可以转化成求对应编号在N-1级城市的坐标。
M mod 22N-2:M编号的城市在N-1级的城市未经过翻转变化前,对应位置的编号。
M / 22N-2:M编号的房屋在4座N-1级的城市中的哪一块区域。对应区域如下:
在这里插入图片描述

求得N-1级的房屋位置(x,y)后,我们需要对根据4个区域进行坐标变化来得到M编号在N级城市的位置,x为行号,y为列号。

方法一:以图的左上角为坐标原点,即所有坐标在同一象限。

区域0: 将原城市顺时针旋转90度,再水平翻转
在这里插入图片描述
这里使用旋转矩阵进行坐标变换,在二维空间中,正角表示逆时针旋转。顺时针旋转90度为负角,
(x,y)->(-y,x)
水平翻转后,
(-y,x)->(y,x),纵坐标不变,横坐标符号改变。

区域1: 将原城市向右平移N-1级城市的边长,边长len与等级N的关系为
len=2N , 所以行号不变,列号加上len
(x,y)->(x,y+len)

区域2: 将原城市向右平移N-1级城市的边长,再向下平移N-1级城市的边长 所以行号和列号均加上len
(x,y)->(x+len,y+len).

区域3: 将原城市逆时针旋转90度,在水平翻转,以左上角为原点逆时针旋转
(x,y)->(y,-x)
水平翻转:
(y,-x)->(-y,-x)
要将其挪到左下角的位置,由于行号和列号都是从0开始
(-y,-x)->(-y+2*len-1,-x+len-1)

代码

#include<iostream>
#include<cmath>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pll;
pll calc(LL N,LL M)//N为城市等级,M为该等级对应的编号
{
    if(N==0) return {0,0};
    //上一级城市的边长和房屋数量
    LL len=1ll<<(N-1);
    LL count=1ll<<(2*N-2);
    pll pos=calc(N-1,M%count);//计算上一级城市
    LL x=pos.first, y=pos.second;
    LL z=M/count;//确定该编号在4块N-1级中的哪一块
    if(z==0) return {y,x};
    if(z==1) return {x,y+len};
    if(z==2) return {x+len,y+len};
    if(z==3) return {2*len-1-y,len-1-x};
}
int main()
{
    
    int n;//数据组数
    cin>>n;
    while(n--)
    {
        LL N,A,B;
        cin>>N>>A>>B;
        pll ac=calc(N,A-1);
        pll bc=calc(N,B-1);//从0开始编号
        LL x=ac.first-bc.first;
        LL y=ac.second-bc.second;
        double dis=sqrt(double((x*x+y*y)))*10;
        printf("%.0lf\n",dis);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值