98. 分形之城 题解

分形之城

题目链接
城市的规划在城市建设中是个大问题。

不幸的是,很多城市在开始建设的时候并没有很好的规划,城市规模扩大之后规划不合理的问题就开始显现。

而这座名为 Fractal 的城市设想了这样的一个规划方案,如下图所示:

图

当城区规模扩大之后,Fractal 的解决方案是把和原来城区结构一样的区域按照图中的方式建设在城市周围,提升城市的等级。

对于任意等级的城市,我们把正方形街区从左上角开始按照道路标号。

虽然这个方案很烂,Fractal 规划部门的人员还是想知道,如果城市发展到了等级 N,编号为 A 和 B 的两个街区的直线距离是多少。

街区的距离指的是街区的中心点之间的距离,每个街区都是边长为 10 米的正方形。

输入格式
第一行输入正整数 n,表示测试数据的数目。

以下 n 行,输入 n 组测试数据,每组一行。

每组数据包括三个整数 N,A,B,表示城市等级以及两个街区的编号,整数之间用空格隔开。

输出格式
一共输出 n 行数据,每行对应一组测试数据的输出结果,结果四舍五入到整数。

数据范围
1≤N≤31,
1≤A,B≤22N,
1≤n≤1000
输入样例:
3
1 1 2
2 16 1
3 4 33
输出样例:
10
30
50

对于这道题,我个人觉得是一道比较难的递归题目,可以很好地加深我们对递归程序的理解。
现在讲一下我做这道题的思路,没有李煜东大神的那么优雅,但是我觉得应该适合广大的朋友,因为我的想法比较基础,使用的语法也很常见。

思路

首先大家的第一想法肯定都是把两个坐标求出来。
那么如何求坐标呢?
由于第n级的城市都是由第n-1级的城市由旋转或者平移组成的
所以我们的主要思路就是将城市降级
因为第n级的城市是由四个第n-1级的城市组成的,
我们可以把第n级的城市划分成四个区

1区2区
4区3区

其中
1区是由第n-1级城市顺时针旋转90度形成的
坐标对应关系为
在第n-1级城市的坐标(x,y)–>在第n级城市的坐标(2^(n-1) +1-y,x)

2区是由第n-1级城市向右平移过来的
坐标对应关系为
在第n-1级城市的坐标(x,y)–>在第n级城市的坐标(2^(n-1) +x,y)

3区是由第n-1级城市向右下方平移而来的
坐标对应关系为
在第n-1级城市的坐标(x,y)–>在第n级城市的坐标(2^(n-1) +x,2^(n-1) + y)

4区是由第n-1级城市逆时针旋转90度形成的
坐标对应关系为
在第n-1级城市的坐标(x,y)–>在第n级城市的坐标 (y,2^n +1-x)

至于我是怎么推出来的,我想大家可以自己去找一找规律。

在得到第n-1级城市和第n级城市的坐标对应关系之后
我们的问题就是变成了求该点第n-1级城市的坐标,再通过坐标转换求出第n级城市的坐标

想要求该点在n-1级城市的坐标,那就必须知道它在分区的编号
现在来解释一下分区编号是个什么东西(这是我自己定义的一个东西)

分区编号:我们把第n级的城市划分成了四个区,分区编号就是该点在每一个区内的编号,现在举个例子,比如在第2级城市,5号点是属于2区,它是2区里的第一个点,所以它在2区内的分区编号就是1。

在得到分区编号之后,我们需要做的就是得到它在第n-1级城市的编号,这样才能求出它在第n-1级城市的坐标。

将分区编号转换成该点在第n-1级城市的编号
2区和3区因为是由第n-1级城市平移而来,该点在第n-1级城市的编号=该点在第n级城市的分区编号

1区和4区因为是由第n-1级城市旋转而来,该点在第n-1级城市的编号=4^(n-1) +1 -该点在第n级城市的分区编号

就这样不断的把城市降级,直到城市的等级变成0
虽然题目中没有第0级城市的说法,但是根据题意,第0级城市应该有4^0及一个点,
显然这个点的坐标就是(1,1),到达递归边界,在从这个点回溯,不断将城市升级,直到等级变为n,最后返回坐标。

这种问题其实是用递归算法来解决的一类经典问题,就是把一个大的问题分解从一个个和它解答
过程类似的子问题,再由子问题的答案一步步推出原问题的答案

流程

知道第n级城市的房屋编号
				|计算分区编号
			   ∨
得到在第n-1级城市的房屋编号
      ……………………
到达边界第0级城市->坐标为(1,1)
			|根据该点在第二级城市的分区,确定坐标转换关系
			∨
得到在第1级城市的坐标
       ……………………
 得到在第n级城市的坐标
 
          递归结束

现在附上代码

#include<iostream>
#include<math.h>
using namespace std;
struct node {
	long long x, y;
};
long long a[100], b[100];
//s为该层递归函数的城市等级,bh为房屋的编号
node location(long long s, long long bh) {
	node ans;
	//城市等级为0,到达边界,返回坐标。
	if (s == 0) {
		ans.x = 1; ans.y = 1;
		return ans;
	}
	//pd为该点在第s级城市的分区
	long long  pd;
	if (bh % a[s - 1] == 0)
		pd = bh / a[s - 1];
	else
		pd = bh / a[s - 1] + 1;
	//nex为该点在第s-1级城市的编号
	long long nex; 
	if(pd==1||pd==4)
		nex = pd * a[s - 1] - bh + 1;
	else
		nex = bh - (pd - 1) * a[s - 1];
	//cun为用来储存该点在第s-1级城市的坐标,用于之后的坐标转换
	node cun = location(s - 1, nex);
	if (pd == 1) {
		ans.x = b[s - 1] + 1 - cun.y;
		ans.y = cun.x;
	}
	if (pd == 2) {
		ans.x = cun.x + b[s - 1];
		ans.y = cun.y;
	}
	if (pd == 3) {
		ans.x = cun.x + b[s - 1];
		ans.y = cun.y + b[s - 1];
	}
	if (pd == 4) {
		ans.x = cun.y;
		ans.y = b[s] + 1 - cun.x;
	}
	return ans;
}
int main() {
	int n;
	cin >> n;
	//预处理2和4的级数
	a[0] = 1;
	b[0] = 1;
	for (int i = 1; i <= 32; i++) {
		a[i] = a[i - 1] * 4;
		b[i] = b[i - 1] * 2;
	}
	for (int i = 1; i <= n; i++) {
		long long c, a, b;
		cin >> c >> a >> b;
		node tx = location(c, a);
		node ty = location(c, b);
		long long pf = (tx.x - ty.x) * (tx.x - ty.x) + (tx.y - ty.y) * (tx.y - ty.y);
		long long ans;
		ans=10*sqrt(pf)+0.5;
		
		cout << ans << endl;
	}
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值