蓝桥杯决赛题目分析之皮亚诺曲线

原题链接 感谢作者
https://blog.csdn.net/qq_43449564/article/details/124584232

皮亚诺曲线介绍

皮亚诺曲线是一条平面内的曲线。

下图给出了皮亚诺曲线的 1 阶情形,它是从左下角出发,经过一个 3 × 3的方格中的每一个格子,最终到达右上角的一条曲线。为了方便计算和理解,我们可以将图片顺时针旋转90度,也就是起点变为peano[0][0]坐标,终点变为peano[2][2]
  在这里插入图片描述在这里插入图片描述

下图给出了皮亚诺曲线的 2 阶情形
在这里插入图片描述
在2阶的皮亚诺曲线中,我们发现了以下规律:

  1. 可以将其划为9个块,每个块为1阶皮亚诺曲线(块索引为偶数),或是1阶皮亚诺曲线的变换形式(块索引为奇数),如下图所示
    在这里插入图片描述在这里插入图片描述
  2. 经过分析我们可以看出1阶皮亚诺曲线的变换形式中的点和原来的皮亚诺曲线是根据x中轴线进行对称变换后得到的结果(因为同为入口,1阶皮亚诺曲线入口为peano[0][0]而1阶皮亚诺曲线的变换形式为peano[2][0])
  3. 9个块的索引按照皮亚诺曲线的回环形状排列从左往右,从上往下依次为(0,1,2,5,4,3,6,7,8)
  4. 经过3,4,5块时,起点为原来的终点,终点为原来的起点,因此需要进行变换,即用包含当前子块的路径长度((blockIndex + 1) * 9 - 当前子块走过的路径 -1) 而若是上下两行则直接计算之前子块走过的路径 + 当前子块走过的路径即可。

答案解析:

/**
 * 皮亚诺曲线解析
 * 
 * 1. 一阶皮亚诺为一个九宫格组成的曲线
 * 2. 二阶皮亚诺为9个一阶皮亚诺组成的矩阵
 * 3. 性质:
 * 		1. 皮亚诺的矩阵大小 为 3 的 (k + 1)幂次方,k为皮亚诺阶层。
 * 		2. 二阶开始的皮亚诺曲线中出现了两种不同类型的一阶皮亚诺曲线
 * 		   这两种不同的皮亚诺曲线关于x中轴线对称。
 * 4.计算两点间距离
 * 		1. 高阶的皮亚诺曲线可以转变成9个k-1阶的皮亚诺曲线
 * 		2. 皮亚诺曲线中两点间的距离可以通过两点到原点的距离差进行计算
 * @author zygswo
 *
 */
public class PeanoGraph {

	/**
	 * 将高次的皮亚诺分割成低一阶层的皮亚诺,其中存放的是区块的索引
	 * 按照皮亚诺曲线的回环形状排列
	 */
	private static int[][] block = new int[][]{
		{0,1,2},{5,4,3},{6,7,8}
	};
	
	/**
	 * blockSize 数组表示每个区块的尺寸
	 */
	private static int blockSize[];
	
	/**
	 * 计算离原点的距离
	 * @param k 皮亚诺的阶层
	 * @param x x
	 * @param y y
	 * @return
	 */
	private static int calc(int k, int x, int y) {
		// 结束递归
		if (k == 0) {
			return 0;
		}
		// 获取当前坐标所在的区块的坐标(即走过了几个子块)
		int blockIndex = block[x / blockSize[k]][ y / blockSize[k]];
		// blockIndex为奇数和偶数表示不同类型的皮亚诺曲线
		if (blockIndex % 2 == 1) {
			// 进行轴变换(例如,原来 在第3行的就到了第1行,原来第二行的就不变)
			x = blockSize[k] - 1 - x % blockSize[k];
		}
		/*
		 *  判断是否当前的点位于中间线上,即block索引为3,4,5
		 *  这时我们发现中间线上的皮亚诺曲线和两边的起点终点位置相反
		 * 	那么中间线上的点到起点的距离即为前面的方块的所有位置和 + 当前块中终点到当前的点距离
		 * 	当前块中终点到当前的点距离 = 当前块的位置和 - 当前块起点到当前的点的位置 
		 *  x % blockSize[k] = x 在当前块中的相对位置
		 *  y % blockSize[k] = y 在当前块中的相对位置
		 */
		if (blockIndex / 3 == 1) {
			return (blockIndex + 1) * blockSize[k] * blockSize[k]
					- 1 - calc(k-1, x % blockSize[k], y % blockSize[k]);
		} else {
			return blockIndex * blockSize[k] * blockSize[k]
					+ calc(k-1, x % blockSize[k], y % blockSize[k]);
		}
	}
	
	private static int abs(int a) {
		return a > 0 ? a : -a;
	}
	
	public static void main(String[] args) {
		// 不同阶级的块的尺寸不同
		blockSize = new int[] {
				0,1,3,9
		};
		// 计算距离
		System.out.println(abs(calc(2,3,0) - calc(2,2,0)));
	}
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zygswo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值