AcWing 98. 分形之城
题目:
城市的规划在城市建设中是个大问题。
不幸的是,很多城市在开始建设的时候并没有很好的规划,城市规模扩大之后规划不合理的问题就开始显现。
而这座名为 Fractal 的城市设想了这样的一个规划方案,如下图所示:
当城区规模扩大之后,Fractal 的解决方案是把和原来城区结构一样的区域按照图中的方式建设在城市周围,提升城市的等级。
对于任意等级的城市,我们把正方形街区从左上角开始按照道路标号。
虽然这个方案很烂,Fractal 规划部门的人员还是想知道,如果城市发展到了等级 N,编号为 A 和 B 的两个街区的直线距离是多少。
街区的距离指的是街区的中心点之间的距离,每个街区都是边长为 10 米的正方形。
输入格式
第一行输入正整数 n,表示测试数据的数目。
以下 n 行,输入 n 组测试数据,每组一行。
每组数据包括三个整数 N,A,B,表示城市等级以及两个街区的编号,整数之间用空格隔开。
输出格式
一共输出 n 行数据,每行对应一组测试数据的输出结果,结果四舍五入到整数。
数据范围
1 < = N < = 31 1<=N<=31 1<=N<=31
1 < = A , B < = 2 2 N 1<=A,B<=2^{2N} 1<=A,B<=22N
1 < = n < = 1000 1<=n<=1000 1<=n<=1000
输入样例:
3
1 1 2
2 16 1
3 4 33
输出样例:
10
30
50
思路:
将编号为 M 的房屋(从0开始编号)在N级城市的坐标记为:calc(N,M)。
在求 calc(N,M)时,因为 N-1级城市有 2 2 N − 2 2^{2N-2} 22N−2 座房子,我们递归求出 calc(N-1,M mod 2 2 N − 2 2^{2N-2} 22N−2),
记求出的位置(x,y)从0开始编号,再根据 M/ 2 2 N − 2 2^{2N-2} 22N−2 的大小算出处于哪一个位置。
1、如果在 左上角 则需要将 N-1 级的城市 顺时针旋转 90° 然后再水平旋转。
由图可知:坐标 由(x,y)变成 ( y , 2 N − 1 − x − 1 y,2^{N-1}-x-1 y,2N−1−x−1) 再变成 (y, x)
2、如果在 右上角 则坐标由 (x,y) 变成 ( x , y + 2 N − 1 x,y+2^{N-1} x,y+2N−1)
3、如果在 右下角 则坐标由 (x,y) 变成 ( x + 2 N − 1 , y + 2 N − 1 x+2^{N-1},y+2^{N-1} x+2N−1,y+2N−1)
4、如果在 左下角 则需要将 N - 1 级城市逆时针旋转90°,再水平旋转
坐标由 (x,y) 变成 ( 2 N − 1 − y − 1 , 2 N − 1 − x − 1 2^{N-1} - y - 1, 2^{N-1}-x-1 2N−1−y−1,2N−1−x−1),根据位置还需要将行号加上 2 N − 1 2^{N-1} 2N−1,
坐标变成( 2 N − y − 1 , 2 N − 1 − x − 1 2^N - y - 1, 2^{N-1}-x-1 2N−y−1,2N−1−x−1)
代码:
package 基本算法.递推与递归.分形之城;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
while(t-- > 0) {
int n = scanner.nextInt();
long A = scanner.nextLong();
long B = scanner.nextLong();
Point ac = calc(n, A - 1);
Point bc = calc(n, B - 1);
double x = ac.getX() - bc.getX(), y = ac.getY() - bc.getY();
System.out.println(Math.round(Math.sqrt(x*x + y*y) * 10));
}
scanner.close();
}
public static Point calc(int n, long m) {
if(n == 0) return new Point(0, 0);
long len = (long)1 << (n - 1), cnt = (long)1 << (2 * n - 2);
Point pos = calc(n - 1, m % cnt);
long x = pos.getX(), y = pos.getY();
long z = m / cnt;
if(z == 0) return new Point(y, x);
if(z == 1) return new Point(x, y + len);
if(z == 2) return new Point(x + len, y + len);
if(z == 3) return new Point(2 * len - y - 1, len - x - 1);
return new Point(-1, -1);
}
}
class Point{
private long x;
private long y;
public Point(long x, long y) {
this.x = x;
this.y = y;
}
public long getX() {
return x;
}
public long getY() {
return y;
}
}