有理数树 递归

十九世纪的时候,Moriz Stern (1858)与Achille Brocot (1860)发明了“一棵树”。据说,经由一些简单的规则而产生的这一棵树上,可以包含零以上所有的有理数。这棵树看起来大致这样:
在这里插入图片描述
你观察出规则了吗?
首先,他们在第一列放两个“分数”,第一个是0 / 1,代表0;第二个是1 / 0,代表无穷大。接着他们一列一列地产生这棵树,当他们要产生第k+1列的时候,就先把前k列所有的分数按照大小排成一列(假设有n个),在这些数之间会有n - 1个间隔,那么第k + 1列就准备产生n - 1个数,其值的分子恰好是左右两个数的分子的和、分母是左右两个数的分母的和。
例如,2 / 3,而它的2就是左边1 / 2的1和右边1 / 1的分子1相加的结果;而2 / 3的3,则是1 / 2的2加上1 / 1的分母1而得。
从这棵树中,我们可以看出,每个正的最简分数在这棵树中恰好出现一次,我们用字母“L”和“R”分别表示从树根(1 / 1)开始的一步“往左走”和“往右走”,则每一个数都可以由L和R组成的序列表示。
例如,LRRL表示从1 / 1开始往左走一步到1 / 2,然后往右走到2 / 3,再往右走到3 / 4,最后往左走到5 / 7。我们可以把LRRL看作5 / 7的一种表示法。几乎每个正分数均有唯一的方法表示成一个由L和R组成的序列。
给定一个分数,输出它的LR表示法。

输入
输入有两个互素的正整数m和n(1 ≤ n,m ≤1000)。
输出
输出对应的LR表示法。

样例输入 Copy
5 7
样例输出 Copy
LRRL

不难发现每个数都可以由上面的树的数据得到,且当前结点的左边一定小于大当前结点,右边大于当前结点。
在这里插入图片描述
就比如 1 / 4 是由 0 / 1 和 1 / 3 得到的 ,可以考虑记录每个节点的值和其左右的结点,让后递归处理即可。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;

int n,m; 
double x;

struct Node
{
	int l1,l2;
	int r1,r2;
	int a,b;
	double y;
}tr[N];

void dfs(int u)
{
//	printf("%f  %f \n",tr[u].y,x);
	if(tr[u].y>x)
	{
		int d1=tr[u].l1+tr[u].a;
		int d2=tr[u].l2+tr[u].b;
		tr[u+1]={tr[u].l1,tr[u].l2,tr[u].a,tr[u].b,d1,d2,d1*1.0/d2};
		printf("L");
		dfs(u+1);
	}
	else if(tr[u].y<x)
	{
		int d1=tr[u].r1+tr[u].a;
		int d2=tr[u].r2+tr[u].b;
		tr[u+1]={tr[u].a,tr[u].b,tr[u].r1,tr[u].r2,d1,d2,d1*1.0/d2};
		printf("R");
		dfs(u+1);		
	}
}

int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);

	cin>>m>>n;
	x=m*1.0/n;

	tr[1]={0,1,1,0,1,1,1.0};
	
	dfs(1);


	return 0;
}










发布了43 篇原创文章 · 获赞 1 · 访问量 1569

猜你喜欢

转载自blog.csdn.net/DaNIelLAk/article/details/105245352
今日推荐