[分治] Stupid Cat & Doge

如何【题目描述】

动物园的规划和城市规划一样是个令人头疼的大问题。不幸的是,动物园规划师R.V.L.先生高估了小动物们的智商,他设计了一个极其复杂的动物园道路规划方案,如下图所示:

动物园按照下述方法进行扩建:当动物园规模扩大之后,R.V.L.先生设计的解决方案是把与原来动物园结构一样的区域复制或旋转90度之后按照图中的方式建设在原来的动物园周围(即将原来的动物园复制一遍放在原动物园上方,将顺时针旋转90度后的动物园放在原动物园的左上方,将逆时针旋转90度后的动物园放在原动物园的左方),再用道路将四部分的首尾连接起来,即可提升动物园的等级。

容易看出,等级提升后的动物园仍然是由一条道路连接,等级为N的动物园共能容纳2^2N只小动物,每只小动物将被分配到唯一的一间房屋。对于任意等级的动物园,我们从左上角开始沿着唯一的道路走,按照道路为房屋标号,就能够得到每间房屋的编号了。

说了这么多,智商余额不足的Stupid cat和Doge早已晕头转向。他们想知道,如果城市发展到了一定等级,他俩各自所处的房屋之间的直线距离是多少。房屋之间的距离是指两座房屋中心点之间的距离,你可以认为每间房屋都是边长为10米的正方形。

输入:包含多组测试数据,第一行有一个整数 T 表示测试数据的数目。每组测试数据包含一行用空格隔开的三个整数 N, S, D,表示动物园等级,Stupid cat分配到的房屋编号和Doge分配到的房间编号。

输出:对于每组测试数据,在单独的一行内输出答案,四舍五入到整数。



【题目分析】

一道有难度的分治题目。首先,我们需要先观察一下:等级1是如何转变为等级2的呢?

{

  如下图所示,我们将等级1分为4个区域。

  将等级2分为4个区域,不难看出,等级2的2区域,3区域完全是等级1的形状。1区域是等级1的顺时针旋转90°,4区域则是1区域的轴对称图形。

  再仔细看,等级2是一个4*4的正方形,即被分为4行4列。

  我们枚举了等级2的所有房子的坐标。如下图。

  举例,1号房子在第1行,第1列,所以1号房子(1,1)(在第一区域),下面的所有房子都可以如此枚举出坐标。

  我们可以得到一个非常难想到的规律(那你是怎么想到的***)

  (此时n是等级),如果一个点在第4区域,那么(2^n)+1=这个房子的(x+y)。且如果是第四块,先对上一等级逆时针旋转,即先顺时针旋转再中心对称。

 

  如果一个点在第1区域旋转后横坐标变成纵坐标。

  如果一个点在第2区域形状和上一等级(现在是等级2,上一等级即等级1)一样无需变化,只需要求出上一等级的横坐标。

  如果一个点在第3区域形状也和上一等级一样,求出上一等级横坐标还要加上半个边长。

 

}

 

贴上此题AC代码。

p.s.   k>>1表示k=k/(2^1)即k/=2。k<<1表示k=k*(2^1)即k*=2。

则k>>2就是k/=4..以此类推。

#include <cmath>
#include <iostream>
#define LL long long int
using namespace std; int base_x[5]={0,1,1,2,2};//第一等级为基底,这是等级1四个房子的所在行,base_y是四个房子的所在列,数组的[0]默认不放为[0]。 int base_y[5]={0,1,2,2,1};//任何等级都由第一等级推过去 long long int k,a,b,t; LL search_y(LL k,LL n);//声明函数 double dis(LL x1,LL y1,LL x2,LL y2){return sqrt(pow(x1-x2,2)+pow(y1-y2,2))*10;}//计算距离函数 LL search_x(LL k,LL n) { if(k==1)return base_x[n];//边界 如果是第一等级 直接返回答案 即该标号横坐标 else{ LL map=pow(2,k<<1);//地图的大小 即k等级的动物园共有几个房屋 int block=(n%(map>>2)==0)?(n/(map>>2)):(n/(map>>2))+1; //计算标号为n的房屋在地图的哪一个方位(左上右上左下右下)特殊条件特殊判断 if(block==1)return search_y(k-1,n);//分类搜索答案 //如果是第一块 旋转后横坐标变成纵坐标 else if(block==2)return search_x(k-1,(n%(map>>2)==0)?n/2:n%(map>>2)); //如果是第二块 形状和上一等级一样无需变化 只是求出上一等级的横坐标即可 else if(block==3)return search_x(k-1,n%(map>>1))+pow(2,k-1); //如果是第三块 形状也一样 求出上一等级横坐标还要加上半个边长 else if(block==4)return pow(2,k)+1-search_y(k-1,n%(map*3/4)); //如果是第四块 逆时针旋转 先顺时针旋转再中心对称。(2^n)+1=这个房子的(x+y) } }/*注释同上*/ LL search_y(LL k,LL n) { if(k==1)return base_y[n]; else{ LL map=pow(2,k<<1); int block=(n%(map>>2)==0)?(n/(map>>2)):(n/(map>>2))+1; if(block==1)return search_x(k-1,n); else if(block==2)return search_y(k-1,(n%(map>>2)==0)?n/2:n%(map>>2))+pow(2,k-1); else if(block==3)return search_y(k-1,n%(map>>1))+pow(2,k-1); else if(block==4)return pow(2,k-1)+1-search_x(k-1,n%(map*3/4)); } } /*注释同上*/ int main() { cin>>t;//数据总量 while(t--){ cin>>k>>a>>b;//读入等级数 StupidCat和Doge的房屋编号 LL x1=search_x(k,a);//求出Cat的房屋横坐标 LL y1=search_y(k,a);//求出Cat的房屋纵坐标 LL x2=search_x(k,b);//求出Doge的房屋横坐标 LL y2=search_y(k,b);//求出Doge的房屋纵坐标 double ans=dis(x1,y1,x2,y2);//计算两者之间的距离 LL temp=ans;//以下是四舍五入计算 cout<<((ans>=temp+0.5)?(temp+1):temp)<<endl; } }

 

转载于:https://www.cnblogs.com/jiandanset/p/7302612.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值