UVa Problem 10183 How Many Fibs? (斐波那契计数)

// How Many Fibs? (斐波那契计数)
// PC/UVa IDs: 110601/10183, Popularity: B, Success rate: average Level: 1
// Verdict: Accepted
// Submission Date: 2011-05-30
// UVa Run Time: 0.012s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net
//
// 很遗憾,不能使用斐波那契数的封闭形式来帮助解决此题,因为封闭形式只能大概估计,有 -1 到 1 的
// 误差。只能老老实实实现大数加法了。这里使用了一点小技巧,定义了一个向量 vector < stri
// ng > fibs,保存计算得到的斐波那契数,预先计算到有 100 位数的斐波那契数,采用字符串比较的
// 方式找到第一个大于等于 a 和最后一个小于等于 b 的斐波那契数在数组中的位置,统计之间包含的斐波
// 那契数即可。

#include <iostream>
#include <sstream>
#include <vector>

using namespace std;

#define UPBOUND 101

vector < string > fibs;

// 比较两个斐波那契数的大小,数位存放在f1和f2中,其中f1的数位是按高位到低位存放,f2的数位
// 是按低位到高位存放。f1大于f2返回1,小于返回-1,等于返回0。
int fibs_compare(string f1, string f2)
{
	if (f1.length() != f2.length())
		return f1.length() > f2.length() ? 1 : (-1);
	
	for (int i = 0, j = f2.length() - 1; i < f1.length(); i++, j--)
		if (f1[i] != f2[j])
			return f1[i] > f2[j] ? 1 : (-1);
	
	return 0;
}

// 根据前两个斐波那契数产生下一个斐波那契数,数位逆序存放于字符串变量f1和f2,最终结果也逆序存放。
string fibs_add(string f1, string f2)
{
	// 前后两个斐波那契数有以下长度关系:f1.length() <= f2.length()。
	string tmp;
	int carry = 0;
	
	for (int i = 0; i < f1.length(); i++)
	{
		carry = (f1[i] - '0') + (f2[i] - '0') + carry;
		char c = '0' + carry % 10;
		tmp.append(1, c);
		carry = carry / 10;
	}
	
	for (int i = f1.length(); i < f2.length(); i++)
	{
		carry = (f2[i] - '0') + carry;
		char c = '0' + carry % 10;
		tmp.append(1, c);
		carry = carry / 10;
	}
	
	if (carry)
		tmp.append(1, '1');
		
	return tmp;
}

// 填充斐波那契数表,直到计算出具有101位数的斐波那契数为止。
void fill_fibs()
{
	string f1 = "1", f2 = "2";
	
	fibs.push_back(f1);
	fibs.push_back(f2);
	
	while (f2.length() < UPBOUND)
	{
		string tmp = fibs_add(f1, f2);
		f1 = f2;
		f2 = tmp;
		fibs.push_back(f2);
	}
}

int main(int ac, char *av[])
{
	// 填充斐波那契数表。
	fill_fibs();

	string a, b, line;
	while (getline(cin, line), line.length())
	{
		istringstream iss(line);
		iss >> a >> b;
		
		if (a == "0" && b == "0")
			break;
		else
		{
			// 找到大于等于a的斐波那契数在fibs数组的位置。
			int start, end;
			for (int i = 0; i < fibs.size(); i++)
			{
				if (a.length() > fibs[i].length())
					continue;
					
				if (fibs_compare(a, fibs[i]) <= 0)
				{
					start = i;
					break;
				}
			}
			
			// 找到小于等于b的斐波那契数在fibs数组的位置。
			for (int i = fibs.size() - 1; i >= 0; i--)
			{
				if (b.length() < fibs[i].length())
					continue;

				if (fibs_compare(b, fibs[i]) >= 0)
				{
					end = i;
					break;
				}
			}

			// 输出总个数。
			cout << (end - start + 1) << endl;
		}
	}
		
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值