首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C语言 >

求帮忙观一道c题,跟斐波那契有点像

2013-06-26 
求帮忙看一道c题,跟斐波那契有点像f(x)0 (x0)f(x)1 (0x1)f(x)f(x-1)+f(x-3.14) (x1)Your work is

求帮忙看一道c题,跟斐波那契有点像
f(x)=0 (x<0)
f(x)=1 (0<=x<1)
f(x)=f(x-1)+f(x-3.14) (x>=1)

Your work is to tell me the result of f(x), is the answer is too large, divide it by 1000000007 and give me the remainder.
Be careful the number x can be an integer or not.
Input

In the first line there is an Integer T(0<T<10000) which means the number of test cases in the input file.
Then followed T different lines, each contains a number x(-1000<x<1000).
Output

For each case of the input file, just output the result, one for each line.

Time Limit: 1 Sec  Memory Limit: 64 MB
直接把题贴在这里啦,大家看看
递归的做法会超时啊T T想不到好的方法,来求助大家~ C
[解决办法]
优化下
1,用数组把中间已经求得的f(x)保存,每次算的时候先检测是否有保存,有保存直接读,没保存在算
 数组2000不超空间
2,每次求出f(x)时都对1000000007 取模,保存也保存取模后的值
[解决办法]
把 x * 100 , 然后就不需要浮点运算了, 然后把 0 <= x <= 1000 * 100 范围全计算出来, 最后就读输入, 查表, 输出就行了...
[解决办法]
事实上最坑爹的是x的定义吧,x可以为单精度,也可以为双精度,一旦涉及到浮点数来比较大小,就难免需要用eps。更坑爹的是这些题特喜欢考eps,各种临界值。
[解决办法]
赶项目 要加班啊 据说还要封闭开发 做开发一年都不到就… 苦逼啊

采用3楼的方法 直接用整数,另外注意,对题中值太大的越界不做检查,仅测试算法速度
先上个递归的,方便测试


int Caculate(int s)
{
if (s < 0)
return 0;
if (s < 100)
return 1;
return Caculate(s - 100) + Caculate(s - 314);
}

上面的代码执行非常慢,当输入5000,也就是题中的50就抗不住了

第二个是中规中矩的算法,把每一步的结果保存在map中,循环计算

int Caculate2(int s)
{
std::map<int, int> mapValues1;
std::map<int, int> mapValues2;
mapValues1[s] = 1;
bool bChanged = true;
int count = 0;
std::map<int, int>* p1;
std::map<int, int>* p2;
while (true)
{
p1 = bChanged ? &mapValues1 : &mapValues2;
p2 = bChanged ? &mapValues2 : &mapValues1;
if (p1->empty())
break;

p2->clear();
for (std::map<int, int>::iterator i = p1->begin(), e = p1->end(); i != e; ++i)
{
if (i->first < 0)
continue;
if (i->first <100)
{
count += i->second;
continue;


}
p2->operator [](i->first - 100) += i->second;
p2->operator [](i->first - 314) += i->second;
}
bChanged ^= true;
}
return count;
}


此算法输入为200000,也就是题中的2000也熬不住了,其中将相同的项合并来提高执行效率

可以将题中的迭代看成完全二叉树,往左为-1,往右为-3.14,那么当节点的值为0-1时,就满足
f(x)=1 (0<=x<1),当然,将二叉树同层的相同值合并,就演化成杨辉三角(亦即二项分布),可以用纯数学的方法

int Caculate3(int s)
{
int x = s / 100 + 1;

int iCount = 0;
for (int i = 1; i <= x; ++i)
{
//对于第i层,有i个数字
int m = s - 100 * (i - 1);
for (int j = 0; j < i; ++j)
{
int r = m - 214 * j; // x = s - (314 * j + 100 * (i - j))
if (r < 0)
break;

if (r < 100)
{
//先计算Ca^b
int a = i - 1;
int b = j;
if (2 * b > a)
b = a - b;
int sum = 1;
int c = 0;
for (int k = a; c < b; --k, ++c)
{
sum *= k;
}
c = 0;
for (int k = 2; c < b - 1; ++k, ++c)
{
sum /= k;
}
iCount += sum;//Ci-1 j
}
}
}
return iCount;
}


上面的算法在输入为2000000,也就是题中的20000时,可以在一秒内计算出,此算法就是用的二项分布
在计算Cm^n时(m中取n个)用的死方法,不知道能不能优化,也没去考虑了。
另外在查找每一层符合条件的点时,可以不从左至右遍历,直接计算,这个优化我就不贴出来了,优化后,可以在1秒算出500W,也就是题中的5W输入。
如果用二叉树结构,可以用层次遍历+剪枝的方式。这个没试,不知道效率怎样。可以在节点中保存位置,以便剪掉同层节点。
另外注意,在二项分布模型中,一层最多有一个节点满足条件。

热点排行