POJ P3889 Fractal Streets

目录:


题目:

传送门


分析:

把第n级分形图看成是一个二维坐标,我们需要求出两个点的坐标,然后,根据两点间的距离公式求结果
首先这是一个分形图肯定需要用到递归思想
我们分别比较第n-1级分形图在第n级分形图中的位置来进行计算第n级分形图的情况(n是级数,s是需要求的编号)


下面就讲下关于递归的一些东西:
当n等于1时(即是最初的那个第1级分形图)
1.当s等于1, x=1,y=1 x = 1 , y = 1
2.当s等于2, x=1,y=2 x = 1 , y = 2
3.当s等于3, x=2,y=2 x = 2 , y = 2
4.当s等于4, x=2,y=1 x = 2 , y = 1
而当我们在递归时的式子,则是分成四种情况:
1.当前编号小于上一级编号总数时
该情况说明当前编号是在n级分形图的左上角,
但是左上角分形图是 n1 n − 1 级分形图逆时针旋转90度得到的
所以我们带入递归式时,需要将x和y,倒一下
不明白的同学可以这样看:
第1级道路: (1,1)>(1,2)>(2,2)>(2,1) ( 1 , 1 ) − > ( 1 , 2 ) − > ( 2 , 2 ) − > ( 2 , 1 )
第2级道路左上角: (1,1)>(2,1)>(2,2)>(1,2) ( 1 , 1 ) − > ( 2 , 1 ) − > ( 2 , 2 ) − > ( 1 , 2 )
两种情况的x和y情况互换了
递归式: find(n1,s,y,x) f i n d ( n − 1 , s , y , x )
2.当编号小于2倍的 n1 n − 1 数目时,说明当前编号s在分形图的右上角
由于右边的分形图没有经过旋转
所以我们直接带入递归式,
需要注意的是我们的编号要减去上一级的编号,
因为我们始终是根据上一级来推出下一级
递归式: find(n1,sp[n1],x,y) f i n d ( n − 1 , s − p [ n − 1 ] , x , y )
递归出来之后,我们的x需要加上上一级的边的大小
这从分形图中很容易看出
x=x+(1<<n1) x = x + ( 1 << n − 1 )
3.当编号小于3倍的 n1 n − 1 数目时,跟第2种情况类似,
只是递归出来之后,x和y都需要加上上一级的边的大小

find(n1,s2p[n1],x,y) f i n d ( n − 1 , s − 2 ∗ p [ n − 1 ] , x , y )
//注意编号必须要小于上一级的大小
// 因为我们是放在上一级的情况下考虑的
x+=(1<<n1) x + = ( 1 << n − 1 )
y+=(1<<n1) y + = ( 1 << n − 1 )
4.最后一种情况,s在第n级分形图的左下角
这种情况跟第2种情况差不多,
我们先按照逆时针的情况来解决,这就跟第1种情况一样了
然后比较坐标x和y的关系,
容易看出,顺时针相比于逆时针
x为 (1<<n)+1x ( 1 << n ) + 1 − x
y为 (1<<(n1))+1y ( 1 << ( n − 1 ) ) + 1 − y


代码:

#pragma GCC optimize("3")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#define LL long long
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
LL p[16];
LL n=read();
void find(LL n,LL s,LL &x,LL &y)
{
    if(n==1)
    {
        if(s==1) x=1,y=1;
        else if(s==2) x=1,y=2;
        else if(s==3) x=2,y=2;
        else x=2,y=1;
        return;
    }
    if(s<=p[n-1])
      find(n-1,s,y,x);
    else if(s<=2*p[n-1])
    {
        find(n-1,s-p[n-1],x,y);
        y+=(1<<n-1);
    }
    else if(s<=3*p[n-1])
    {
        find(n-1,s-2*p[n-1],x,y);
        x+=(1<<n-1);
        y+=(1<<n-1);
    }
    else 
    {
        find(n-1,s-3*p[n-1],y,x);
        x=(1<<n)+1-x;
        y=(1<<n-1)+1-y;
    }
    return;
}
int main()
{
    LL bx,by,cx,cy;
    p[1]=4;
    for(int i=2;i<=15;i++) p[i]=p[i-1]*4;
    while(n>0)
    {
        LL a=read(),b=read(),c=read();
        find(a,b,bx,by);
        find(a,c,cx,cy);
        printf("%.0f\n",sqrt((bx-cx)*(bx-cx)+(by-cy)*(by-cy))*10);
        n--;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值