分形之城

分形之城

有一座城市如图所示,

1

等级为1的城市已经给出,第i-1级城市升高到第i级城市的做法是将i-1级城市复制一份向下平移到与原城市上端与之对齐,然后将其复制一份向右平移到与原城市左端对其,在沿其中心顺时针旋转90度,最后再复制一份,逆时针沿中心旋转90度,然后平移到已经处理好的三座城市的左下角,最后用道路把城市首尾连接起来,然后从左上角第一座房子沿道路出发依次给房子编号\(1\sim n\),可以参考上图,现在询问n级城市的房屋a和房屋b的直线距离,\(n\leq 31\)

[注:本人语文不行,题目可能没说清楚,最好参考原题]

以下为了代码实现的方便,将所有城市的编号全部-1

显然是一个无限分形图,于是首要考虑递归法,不妨定义\(calc(n,m)\)为房屋m在n级城市中的坐标,我们把坐标原点定在城市中心,x轴水平方向,y轴竖直方向,通过找规律容易知道第i级城市的房屋数\(2^{2n}\)个,因为n级城市是由4个n-1级相同城市组成,只是发生的旋转,可以把子问题看作n-1级城市,容易知道房屋m在n-1级城市中编号应该为\(n\% 2^{2n-2}\)

现在关键在于如何通过\(calc(n-1.m\% 2^{2n-2})\)求出\(calc(n,m)\)

现在需要分类讨论,m在n级城市中的那一块,不妨左上角记为0,右上角记为1,右下角记为2,左下角记做3,记\(calc(n-1,m\% 2^{2n-2})\)\((x,y)\),于找规律结合平面直角坐标系的知识有(其中找规律有n级城市的边长为\(2^n\))

\(calc(n,m)=\begin{cases}(-y-2^{n-2},-x+2^{n-2})(m\% 2^{2n-2}==0)\\(x+2^{n-2},y+2^{n-2})(m\% 2^{2n-2}==1)\\(x+2^{n-2},y-2^{n-2})(m\% 2^{2n-2}==2)\\(y-2^{n-2},x-2^{n-2})(m\% 2^{2n-2}==3)\end{cases}\)

以此依据递归处理即可,时间复杂度\(O(n)\)

参考代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#define il inline
#define ri register
#define ll long long
#define lb long double
using namespace std;
struct pos{
	ll x,y;
}beg[4];
ll base[63];
il lb dis(pos,pos);
il pos divide(int,ll);
int main(){
	beg[0]=(pos){-5,5},beg[1]=(pos){5,5};
	beg[2]=(pos){5,-5},beg[3]=(pos){-5,-5};
	base[0]=1;int lsy,n;ll a,b;scanf("%d",&lsy);
	for(int i(1);i<63;++i)base[i]=base[i-1]<<1;
	while(lsy--)
		scanf("%d%lld%lld",&n,&a,&b),--a,--b,
			printf("%.0Lf\n",dis(divide(n,a),divide(n,b)));
	return 0;
}
il lb dis(pos a,pos b){
	return sqrt(pow(a.y-b.y,2)+pow(a.x-b.x,2));
}
il pos divide(int n,ll m){
	if(n==1)return beg[m];
	pos a(divide(n-1,m%base[2*n-2]));switch(m/base[2*n-2]){
	case 0:return (pos){-a.y-base[n-2]*10,-a.x+base[n-2]*10};break;
	case 1:return (pos){a.x+base[n-2]*10,a.y+base[n-2]*10};break;
	case 2:return (pos){a.x+base[n-2]*10,a.y-base[n-2]*10};break;
	case 3:return (pos){a.y-base[n-2]*10,a.x-base[n-2]*10};break;
	}
}

posted @ 2019-07-18 11:38  a1b3c7d9  阅读(185)  评论(0编辑  收藏  举报