分型之城(POJ3889 Fractal Streets)
老延让刷到23页...话说就我这效率感觉刷不完orz
依旧是原题链接:POJ3889
话说为什么POJ上纯英文啊,这对于我这种看不懂的很有影响啊
没有百度翻译讨论都能认成提交哇QAQ
题目:
城市的规划在城市建设中是个大问题。
不幸的是,很多城市在开始建设的时候并没有很好的规划,城市规模扩大之后规划不合理的问题就开始显现。
而这座名为 Fractal 的城市设想了这样的一个规划方案,如下图所示:
当城区规模扩大之后,Fractal 的解决方案是把和原来城区结构一样的区域按照图中的方式建设在城市周围,提升城市的等级。
对于任意等级的城市,我们把正方形街区从左上角开始按照道路标号。
虽然这个方案很烂,Fractal 规划部门的人员还是想知道,如果城市发展到了等级 N,编号为 A 和 B 的两个街区的直线距离是多少。
街区的距离指的是街区的中心点之间的距离,每个街区都是边长为 10 米的正方形。
输入格式
第一行输入正整数n,表示测试数据的数目。
以下nn行,输入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级城市复制粘贴4份并且各种旋转得来的
用画图简单明了的表示一下↓
但你其实做到最后会发现扩建时如何旋转并没有什么关系因为要重新编号
这道题要求两个房子的直线距离,我们也可求出两个房子分别的坐标,直接勾股定理来求
然后呢这其实是道典型的分形题,根据分形自相似的性质,我们可以很容易的想到使用分治来解决
因为一座N级城市有22N座房子(这原因就不用我说了哇,用2的次方表示是为了位运算方便),我们先将问题缩小到N-1级城市(即使用M%22N-2(N-1级城市的总城市数)求得在N-1级城市中M的编号),求得答案之后根据M/22N-2来确定M在四座N-1城市中的哪一座,从而求解答案。
然后是最麻烦的变换编号:
为了说清楚我特意使用了表格来帮忙:
为了方便计算我们从0开始编号(坐标也是) 简化了一下然后有:
为了方便观看:
然后来观察坐标的变化,设坐标为(x,y),则有:
若位于第一座城市(即左上角的),很明显,整体坐标向右旋转了90度再水平翻转(...),总之最后你会发现坐标左右翻转了,所以坐标变为(y,x)
若位于第二座城市(右上角的),这个比较简单,就是向右平移了2N-1,得到坐标(x,y+2N-1)
若位于第三座城市(右下角的),也比较简单,就是向右平移了2N-1,然后向下平移了2N-1座城市,得到坐标(x+2N-1,y+2N-1)
若位于第四座城市(左下角的),这个较为麻烦...坐标整体向左旋转90度再水平翻转,得到(2N-1-y-1,2N-1-x-1),然后向下平移2N-1,得到(2N-1+2N-1-y-1,2N-1-x-1),即(2N-y-1,2N-1-x-1)
关于坐标顺/逆时针旋转:
具体过程较为复杂我懒得写,给你们一个链接自己看去吧:大佬视频,大概在14分55秒左右~
然后附AC代码~
#include<cmath> #include<cstdio> #include<string> #include<utility> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll;//懒得打字 pair<ll,ll>calc(ll n,ll m) { if(n==0) return make_pair(0,0);//边界 ll len=1ll<<(n-1),cnt=1ll<<(2*n-2); pair<ll,ll> zb=calc(n-1,m%cnt); ll x=zb.first,y=zb.second; ll z=m/cnt; switch(z) { case 0:return make_pair(y,x);break; case 1:return make_pair(x,y+len);break; case 2:return make_pair(x+len,y+len);break; case 3:return make_pair(2*len-y-1,len-x-1);break; } } int main() { int t; scanf("%d",&t); while(t--) { ll n,s,d; scanf("%lld%lld%lld",&n,&s,&d);//不加ll害死人 pair<ll,ll> zb; pair<ll,ll> bz; double ans=0; zb=calc(n,s-1);//记得-1QWQ bz=calc(n,d-1); ll x,y; x=(zb.first-bz.first),y=(zb.second-bz.second);//边长居然是10 ans=sqrt(x*x+y*y)*10;//喜闻乐见 勾股定理 printf("%.0f\n",ans);//四舍五入 } return 0; } /* 输入: 10 3 62 11 5 252 21 3 57 27 3 32 47 3 46 56 3 21 42 5 802 297 5 507 802 5 403 555 3 53 35 输出: 36 92 63 30 32 61 228 136 152 20 */
啊终于写完了累死我了
话说徐大佬他们现在刷的速度应该没有我快
不慌
溜了溜了