0
点赞
收藏
分享

微信扫一扫

蓝桥杯 黄金连分数

伢赞 2022-03-26 阅读 66

蓝桥 2013_4_黄金连分数

【难度:中等】
【考点:斐波那契数列 大整数加减除】

题目

对于某些精密工程,常数的精度很重要。也许你听说过哈勃太空望远镜,它首次升空后就发现了一处人工加工错误,对那样一      个庞然大物,其实只是镜面加工时有比头发丝还细许多倍的一处错误而已,却使它成了“近视眼”!!
言归正传,我们如何求得黄金分割数的尽可能精确的值呢?有许多方法。

比较简单的一种是用连分数:

              1
黄金数 = ---------------------
                    1
         1 + -----------------
                      1
             1 + -------------
                        1
                 1 + ---------
                      1 + ...                    

这个连分数计算的“层数”越多,它的值越接近黄金分割数。

请你利用这一特性,求出黄金分割数的足够精确值,要求四舍五入到小数点后100位。

小数点后3位的值为:0.618
小数点后4位的值为:0.6180
小数点后5位的值为:0.61803
小数点后7位的值为:0.6180340    (注意尾部的0,不能忽略)

你的任务是:写出精确到小数点后100位精度的黄金分割值。

注意:尾数的四舍五入! 尾数是0也要保留!

显然答案是一个小数,其小数点后有100位数字,请通过浏览器直接提交该数字。 注意:不要提交解答过程,或其它辅助说明类的内容。

C++代码

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
//思路:由黄金连分数可转化为求解斐波那契数,运用大数运算求解小数点后一百位
 
//n表示斐波那契数列第一百项
int n = 100; 
int cmp(string a, string b)
{
	if (a == b) return 0;
	else if (a.length() < b.length()) return -1;
	else if (a.length() > b.length()) return 1;
	else
	{
		if (a > b) return 1;
		if (a < b) return -1;
		return -1;
	}
}
 
//大数相加,较大斐波那契数无法算出,只能通过大数计算
string add(string a, string b)
{
	//去掉开头的0,substr(a,n) 返回第a位开始长度为n的字符串
	//find_first_not_of("abc")返回最先匹配到abc任意一个字符的最后位置
	a = a.substr(a.find_first_not_of('0'));
	b = b.substr(a.find_first_not_of('0'));
 
	long long lenA = a.length();
	long long lenB = b.length();
	long long len = max(lenA, lenB) + 10;
	//反转, 便于从最低位逐位求和
	reverse(a.begin(), a.end());
	reverse(b.begin(), b.end());
	string ans(len, '0');
	for (int i = 0; i < lenA; i++)
	{
		ans[i] = a[i];
	}
	//通过模拟手工计算来进行大数相加,temp用来存储上下两位相加的结果
	int temp = 0;
	for (int i = 0; i < len; i++)
	{
		if (i < lenB)
		{
			temp += ((ans[i] - '0') + (b[i] - '0'));
			ans[i] = temp % 10 + '0';
			temp /= 10;
		}
		else
		{
			temp += (ans[i] - '0');
			ans[i] = temp % 10 + '0';
			temp /= 10;
		}
	}
	//ans存储的结果最后要反转回来去掉开头的0
	reverse(ans.begin(), ans.end());
	return ans.substr(ans.find_first_not_of('0'));
}
 
//大数相减
string substract(string a, string b)
{
	//a必须大于b,实际上在divide()中,a已经>=b了
	reverse(a.begin(), a.end());
	reverse(b.begin(), b.end());
	//将a复制给ans
	string ans = a;
	//依旧是模拟手工减法计算
	for (int i = 0; i < b.length(); i++)
	{
		if (ans[i] >= b[i])
		{
			ans[i] = ans[i] - b[i] + '0';
		}
		//注意:在被减数不够减的情况下,需要向前借位,
		//可能被借位为0也不够借,继续往前寻找不为0的位,通过一个while循环实现
		else
		{
			int k = 1;
			while (ans[i + k] == '0')
			{
				//0被借位变为9
				ans[i + k] = '9';
				k++;
			}
			//最终i+k位不为0可以被借-1,i位+10
			ans[i + k] = ans[i + k] - 1;
			ans[i] = ans[i] + 10 - b[i] + '0';
		}
	}
	reverse(ans.begin(), ans.end());
	return ans.substr(ans.find_first_not_of('0'));
}
 
//大数相除
string divide(string a, string b)
{
	//前提 a < b 实际题目已满足
	//大数除法实际上是模拟除法运算结合大数减法
	string ans = "0.";
	for (int i = 0; i < 101; i++) //保留101项,保证四舍五入
	{
		// (a*10)/b = t 不过其中除法用减法substract代替
		a.append(1,'0');
		int t = 0;
		while (cmp(a, b) >= 0)
		{
			a = substract(a, b);
			t++;
		}
		ans.append(1,t + '0');
	}
	return ans;
}
int main()
{
	//斐波那契数列前两项
	string a = "1";
	string b = "1";
	for (int k = 0; k < 40; k++)
	{
		//求解斐波那契数列100-140各项与前一项的比值(所谓黄金连分数)
		for (int i = 3; i < n+k; i++)
		{
			string temp = b;
			b = add(a, b);
			a = temp;
		}
		
		string ans = divide(a, b);
		cout << 100+k  << "项  " <<ans << endl;
	}
 
	return 0;
}

运行结果

在这里插入图片描述

举报

相关推荐

0 条评论