[poj3889]Fractal Streets

转载请说明出处:http://blog.csdn.net/ben_xsy/article/details/79288058#%E4%BB%A3%E7%A0%81

目录

题目描述

题目链接:传送门
给你一个原始的分形图,t组数据,对于每组数据,输入3个数n,h,o
(n为在第n级,h,o为两个房子的编号)
求在第n级情况下,编号为h和o的两个点之间的距离*10为多少
其中,第n级分形图形成规则如下:

  1. 首先先在右下角和右上角复制一遍n-1情况下的分形图
  2. 然后将n-1情况下的分形图逆时针旋转90度,放到左上角
  3. 最后将n-1情况下的分形图顺时针旋转90度,放到左下角
  4. 按照上述规则形成n级分形图

编号是从左上角那个点开始计1,沿着道路计数

解题思路

把第n级分形图看成是一个二维坐标,我们需要求出两个点的坐标,然后,根据两点间的距离公式求结果

首先这是一个分形图肯定需要用到递归思想
我们分别比较第n-1级分形图在第n级分形图中的位置来进行计算第n级分形图的情况(n是级数,s是需要求的编号)

递归边界:

当n等于1时(即是最初的那个第1级分形图)
    1.当s等于1,x=1,y=1
    2.当s等于2,x=1,y=2
    3.当s等于3,x=2,y=2
    4.当s等于4,x=2,y=1

递归式:

1.当前编号小于上一级编号总数时
  该情况说明当前编号是在n级分形图的左上角,
  但是左上角分形图是n-1级分形图逆时针旋转90度得到的
  顾我们带入递归式时,需要将x和y,倒一下

  不明白的同学可以这样看:
  第1级道路:(1,1)->(1,2)->(2,2)->(2,1)
  第2级道路左上角:(1,1)->(2,1)->(2,2)->(1,2)
  两种情况的x和y情况互换了

  递归式: rec(n-1,s,y,x);

2.当编号小于2倍的n-1数目时,说明当前编号s在分形图的右上角
  由于右边的分形图没有经过旋转
  所以我们直接带入递归式,
  需要注意的是我们的编号要减去上一级的编号,
  因为我们始终是根据上一级来推出下一级
  递归式:rec(n-1,s-p[n-1],x,y);
  递归出来之后,我们的x需要加上上一级的边的大小
  这从分形图中很容易看出
  即x=x+(1<<n-1);
3.当编号小于3倍的n-1数目时,跟第2种情况类似,
  只是递归出来之后,x和y都需要加上上一级的边的大小
  即
      rec(n-1,s-2*p[n-1],x,y);
      //注意编号必须要小于上一级的大小
      // 因为我们是放在上一级的情况下考虑的
      x+=(1<<n-1);
      y+=(1<<n-1);
4.最后一种情况,s在第n级分形图的左下角
  这种情况跟第2种情况差不多,
  我们先按照逆时针的情况来解决,这就跟第2种情况一样了
  然后比较坐标x和y的关系,
  容易看出,顺时针相比于逆时针
      x映射为(1<<n)+1-x
      y映射为(1<<(n-1))+1-y
  可以观察分形图,这个地方有点难理解
  可以比较坐标来理解

最后,两个点分别调用递归式,就可以计算出距离了

提交的时候选择G++,poj的c++不知道为什么会编译错误

代码

#pragma comment(linker,"/STACK:102400000,102400000")
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <list>
#include <math.h>
#include <vector>
#include <algorithm>
#include <time.h>
#include <map>
#include <set>
#include <stack>
#include <stdlib.h>
#include <ctype.h>
#include <queue>
#include <bitset>
using namespace std;
#define ll long long
#define ull unsigned long long
#define PI acos(-1.0)
#define E 2.7182818284590452353602874713527
#define si(x) scanf("%d",&x)
#define sl(x) scanf("%lld",&x)
#define pi(x) printf("%d\n",x)
#define pl(x) printf("%lld\n",x)
#define bg(x) cout<<x<<"@@@"<<endl
#define lowbit(x) ((x)&(-(x)))
#define inf 0x3f3f3f3f
#define pii pair<int,int>


ll p[40];    //一直算到4的32次方,代表第n级分形图编号总数目
void rec(ll n,ll s,ll &x,ll &y) //n为第n级,编号是s,横坐标x,纵坐标y,注意x和y要引用
{
    if(n==1)    //递归边界
    {
        if(s==1)x=1,y=1;
        else if(s==2)x=1,y=2;
        else if(s==4)x=2,y=1;
        else x=2,y=2;
        return;
    }
    if(s<=p[n-1])   //分类讨论四种情况
    {
        rec(n-1,s,y,x);
    }
    else if(s<=2*p[n-1])
    {
        rec(n-1,s-p[n-1],x,y);
        y+=(1<<n-1);
    }
    else if(s<=3*p[n-1])
    {
        rec(n-1,s-2*p[n-1],x,y);
        x+=(1<<n-1);
        y+=(1<<n-1);
    }
    else
    {
        rec(n-1,s-3*p[n-1],y,x);
        x=(1<<n)+1-x;
        y=(1<<n-1)+1-y;
    }
}
int main()
{
    p[1]=4;
    for(int i=2;i<=33;i++)p[i]=4*p[i-1]; //初始化
    int t;
    si(t);
    while(t--)
    {
        ll s,e,n,sx,sy,ex,ey;
        scanf("%lld%lld%lld",&n,&s,&e);
        rec(n,s,sx,sy); //分别求出s和e的坐标
        rec(n,e,ex,ey);
        printf("%.0f\n",sqrt((sx-ex)*(sx-ex)+(sy-ey)*(sy-ey))*10);
    }

}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值