分形问题
题意
城市的规划在城市建设中是个大问题。
不幸的是,很多城市在开始建设的时候并没有很好的规划,城市规模扩大之后规划不合理的问题就开始显现。
而这座名为 Fractal 的城市设想了这样的一个规划方案,如下图所示:
当城区规模扩大之后,Fractal 的解决方案是把和原来城区结构一样的区域按照图中的方式建设在城市周围,提升城市的等级。
对于任意等级的城市,我们把正方形街区从左上角开始按照道路标号。
虽然这个方案很烂,Fractal 规划部门的人员还是想知道,如果城市发展到了等级 N,编号为 A 和 B 的两个街区的直线距离是多少。
街区的距离指的是街区的中心点之间的距离,每个街区都是边长为 10 米的正方形。
输入格式
第一行输入正整数 n,表示测试数据的数目。
以下 n 行,输入 n 组测试数据,每组一行。
每组数据包括三个整数 N,A,B,表示城市等级以及两个街区的编号,整数之间用空格隔开。
输出格式
一共输出 n 行数据,每行对应一组测试数据的输出结果,结果四舍五入到整数。
数据范围
1≤N≤31
1≤A,B≤\(2^{2N}\)
1≤n≤1000
输入样例:
3
1 1 2
2 16 1
3 4 33
输出样例:
10
30
50
分析
这道题的意思是告诉我们城市等级和两个编号,求这两个编号的距离。因为求距离需要知道坐标,所以等价于求每个编号的二维坐标是多少。
观察图形得知,我们可以发现每个图形都可以四等分,而且图形四等分后,都可以由前一个图形的来。例如,我们将等级二的图形四等分,则可以分别由图形一直接得到,或者通过对角线,反对角线轴对称后得到。同理,图形三和图形二也有这种联系。因此,对于一个图形我们可以先分治求解子问题的答案,然后得到这个编号在子问题中的坐标后,根据位置关系进行坐标偏移或变换,就可以得到在原图形中的坐标了。递归终点是图形的等级为0,返回的坐标是{0,0}。
总的时间复杂度\(O(n^{1/2})\),即递归深度。
这道题有一个值得注意的点,我们需要将坐标减一,从0开始,这样才能和子问题的坐标对应。
代码
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
struct Point{ll x,y;};
Point get(ll n,ll a)
{
if(!n)return {0,0};
ll block=1ll<<2*n-2,id=a/block;
auto p=get(n-1,a%block);
ll x=p.x,y=p.y,len=1ll<<n-1;
if(id==0)return{y,x};
if(id==1)return{x,y+len};
if(id==2)return{x+len,y+len};
return{2*len-1-y,len-1-x};
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
ll n,a,b;scanf("%lld%lld%lld",&n,&a,&b);
auto p1=get(n,a-1),p2=get(n,b-1);
ll dx=p1.x-p2.x,dy=p1.y-p2.y;
double ans=sqrt(dx*dx+dy*dy)*10;
printf("%.0lf\n",round(ans));
}
return 0;
}