2013年第四届蓝桥杯C++B组省赛D题
黄金连分数
黄金分割数0.61803… 是个无理数,这个常数十分重要,在许多工程问题中会出现。有时需要把这个数字求得很精确。
对于某些精密工程,常数的精度很重要。也许你听说过哈勃太空望远镜,它首次升空后就发现了一处人工加工错误,对那样一个庞然大物,其实只是镜面加工时有比头发丝还细许多倍的一处错误而已,却使它成了“近视眼”!!
言归正传,我们如何求得黄金分割数的尽可能精确的值呢?有许多方法。
比较简单的一种是用连分数:
这个连分数计算的“层数”越多,它的值越接近黄金分割数。
请你利用这一特性,求出黄金分割数的足够精确值,要求四舍五入到小数点后100位。
小数点后3位的值为:0.618
小数点后4位的值为:0.6180
小数点后5位的值为:0.61803
小数点后7位的值为:0.6180340
(注意尾部的0,不能忽略)
你的任务是:写出精确到小数点后100位精度的黄金分割值。
注意:尾数的四舍五入! 尾数是0也要保留!
显然答案是一个小数,其小数点后有100位数字,请通过浏览器直接提交该数字。
注意:不要提交解答过程,或其它辅助说明类的内容。
这个是fib的相邻比值。
不能用递归=-=会爆栈。
这个转化成fib的相邻比值。
分析的话可以根据式子。先把后面去掉。然后一项一项求。
比如枚举一下。
比值分别为1/1, 1/2, 2/3, 3/5, 5/8, 8/13…
很容易发现分母和分子的比值都是fib的数字=-=
第二点是保留到100位。应该对应到fib的哪一项才精确。
fib足够大的话已经不满足c的数据类型的要求。所以。
需要自己定义字符串来存储,以及写一套字符串的加法减法(除法可以转换位减法的)
用C语言的话。。。不在无比熟练的情况下,可能完成不了。
C++或者Java可以考虑一下
Java内部把什么什么的函数都已经跟你写好了。。
比较方便。。因为这是一道填空题。
这个地方用C++写。
加法,减法,除法。。。
这里的除法都可以转化为减法。
这个一个小tips:
不管加法还是减法。
在不知道位数的情况下
从低位开始加。直接反转就可以了从低位开始操作了。
除法转化为减法。这个地方是把fib的低位当作a,fib的高位当作b。
然后b一定大于a。
在做除法的过程中,模拟一下,所以给a在后缀直接加一个0.
直到a >= b为止。
然后开始逐层递减。
记录计算出来的小数位数。然后把它加到ans中就行~
append()是在字符串末尾追加
find_first_not_of()是指找到第一个不等于字符的位置。如果都符合就会返回string::npos
stringstream是串流
i2s代表把数字转化成字符串。stringstream这个东西还挺好用的
代码部分啦~
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
string add(string a, string b)
{
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
a.substr(a.find_first_not_of('0'));
b.substr(a.find_first_not_of('0'));
int lena = a.length();
int lenb = b.length();
int len = max(lena, lenb) + 10;
string ans(len, '0');
for (int i = 0; i < lena; i++)
{
ans[i] = a[i];
}
int temp = 0;
for (int i = 0; i < len; i++)
{
if (i < lenb)
{
temp += (ans[i] - '0') + (b[i] - '0');
}
else
{
temp += (ans[i] - '0');
}
ans[i] = (temp % 10) + '0';
temp /= 10;
}
reverse(ans.begin(), ans.end());
return ans.substr(ans.find_first_not_of('0'));
}
void i2s(int t, string &temp)
{
stringstream ss;
ss << t;
ss >> temp;
}
int comp(string a, string b)
{
if (a.length() > b.length())
{
return 1;
}
if (a.length() < b.length())
{
return -1;
}
else
{
if (a == b)
{
return 0;
}
else if (a > b)
{
return 1;
}
else
{
return -1;
}
}
}
string substract(string a, string b)
{
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
for (int i = 0; i < b.length(); i++)
{
if (a[i] >= b[i])
{
a[i] = a[i] - b[i] + '0';
}
else
{
int k = 1;
while (a[i + k] == '0')
{
a[i + k] = '9';
k++;
}
a[i + k] = a[i + k] - '1' + '0';
a[i] = (a[i] - b[i] + 10) + '0';
}
}
reverse(a.begin(), a.end());
if (a.find_first_not_of('0') == string::npos)
{
return "0";
}
return a.substr(a.find_first_not_of('0'));
}
string divide(string a, string b)
{
string ans = "0.";
int t;
for (int i = 0; i < 101; i++)
{
a.append("0");
t = 0;
while (comp(a, b) >= 0)
{
a = substract(a, b);
t++;
}
string temp;
i2s(t, temp);
ans.append(temp);
}
return ans;
}
int main()
{
string a = "1";
string b = "1";
for (int i = 3; i < 101; i++)
{
string temp;
temp = b;
b = add(a, b);
a = temp;
}
cout << divide(a, b) << endl;
return 0;
}