poj3889 Fractal Streets(递归)(分治)

题意

给你一个原始的分形图,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=1的图形通过旋转、平移构成的。
我们用dfs(n,k)来求n级城市中编号为k位置,从而确定其在n+1级城市中的位置。接下来就分4种情况进行讨论:
1、左上角:可以发现,通过逆时针旋转,x和y反了过来;
2、左下角:可以看成是左上角旋转180后的结果,所以先按左上角来求得坐标,再进行180的翻转;
3、右上角:只需要平移即可;
3、右上角:只需要平移即可。

最终的状态n=1,按图中给x,y赋值就好了。


我的错误

该用ll的地方容易顺手打成int。


代码

#include<math.h>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;


ll myround(double x)//四舍五入 
{
	return x>=0?floor(x+0.5):ceil(x-0.5);
}


double dis(ll x1,ll y1,ll x2,ll y2)
{
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}


ll bc[40];//bc[i]表示i级城市的边长 
void dfs(ll n,ll k,ll &x,ll &y)//x,y引用进入递归 
{
	if(n==1)//递归边界 
	{
		if(k==1) x=1,y=1;
		else if(k==2) x=1,y=2;
		else if(k==3) x=2,y=2;
		else x=2,y=1;
		return ;
	}
	
	ll sz=(bc[n]>>1)*(bc[n]>>1);
	if(k<=sz)//左上 
	{
		dfs(n-1,k,y,x);
	}
	else if(k<=2*sz)//右上 
	{
		dfs(n-1,k-sz,x,y);
		y+=bc[n]>>1;
	}
	else if(k<=3*sz)//右下 
	{
		dfs(n-1,k-2*sz,x,y);
		x+=bc[n]>>1;y+=bc[n]>>1;
	}
	else//左下 
	{
		dfs(n-1,k-3*sz,y,x);
		x=bc[n]+1-x;y=(bc[n]>>1)+1-y;
	}
}


int main()
{
	bc[1]=2;for(int i=2;i<=33;i++) bc[i]=bc[i-1]<<1;
	
	int T;
	scanf("%d",&T);
	while(T--)
	{
		ll n,s,t;
		scanf("%lld%lld%lld",&n,&s,&t);
		ll sx,sy,tx,ty;
		dfs(n,s,sx,sy);
		dfs(n,t,tx,ty);
		ll ans=myround(dis(sx,sy,tx,ty)*10);
		printf("%lld\n",ans);
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/a_bright_ch/article/details/81060208