赞
踩
解决这个问题的其中一个方法是用树的思想,假设三种颜色分别为1,2,3,第一个小球颜色为1,则如下面的图片所示:
(为叙述方便,不妨设f1(n)=f(n),f2(n)=g(n))
根据递推式g(n)=2f(n-1)-g(n-1),可以得出g(n)的表达式
所以我们易知所有的涂色种数为g(n)*3种。
我们需要编程来实现当n(1<=n<=10000)时,总共的涂色种数,由于结果过大,故只需输出结果与1000000007的余数即可,但是本人在编程时遇到以下问题
(1).中间计算过程所需数据的位数过大,发生数据溢出。
这个问题可以用BigInteger类进行解决。但是用这个类的话需要多次压栈,所以运算效率很低,尽管如此,我也必须用这个类进行处理。
(2).既然是递推式,那么需要用递归减少代码量,但是如果用递归的话,更需要多次压栈,又一次大大的降低了运算效率。结果更可怕,发生了堆栈溢出。
这个问题我用了把递归拆开的方法,呵呵,虽然挺笨,但是结果却解决了堆栈溢出的问题。
综上所述我的代码如下:
这是至今为止我能想到的唯一解决方案,我觉得应该有更好的解决方案,其中包括算法的选择,大数据的处理方式,以及递推堆栈溢出的解决方案。注意,必须保证测试时n能取到10000才行。毕竟这样测试虽然能出结果,但总共花了30秒才能运行出结果,运行效率太慢了。这个问题有待解决......
接上,经过我的虚心请教和 勇于实践,终于在一定程度上解决了这个效率问题,毕竟一个程序30秒出结果却是有些夸张。
具体算法如下:
g(n)=2*f(n-1)-g(n-1)
=2*f(n-1)-(2*f(n-2)-g(n-2))
=2*(f(n-1)-f(n-2))+g(n-2)
=2*(f(n-1)-f(n-2))+(2*f(n-3)-g(n-3))
=2*(f(n-1)-f(n-2)+f(n-3))-g(n-3)
=2*(f(n-1)-f(n-2)+f(n-3)-f(n-4))+g(n-4)
=...............
=2*(f(n-1)-f(n-2)+f(n-3)-f(n-4)+f(n-5)-f(n-6)+...(+/-)f(2))(-/+)g(2)
令s= f(n-1)-f(n-2)+f(n-3)-f(n-4)+f(n-5)-f(n-6)+...(+/-)f(2)
则g(n)=2*s(-/+)g(2)
因此,只需设计一个函数实现s即可
当n 为奇数时,则1~n为n个数即奇数个数,则2~n-1为奇数个数,此时,f(2)与f(n-1)同号,而g(2)与f(2)异号
s= f(n-1)-f(n-2)+f(n-3)-f(n-4)+f(n-5)-f(n-6)+...+f(2) ; g(n)=2*s-g(2)
当n 为偶数时,则1~n为n个数即偶数个数,则2~n-1为偶数个数,此时,f(2)与f(n-1)异号,而g(2)与f(2)异号
s= f(n-1)-f(n-2)+f(n-3)-f(n-4)+f(n-5)-f(n-6)+...-f(2) ; g(n)=2*s+g(2)
针对此算法,我的代码如下:
import java.util.Scanner;
import java.math.BigInteger;
接上,我发现一个算法如果人算的越多,计算计算的就越少,为什么这么说呢?
由于g(n)=2*s(+/-)g(2)
当n 为奇数时,则1~n为n个数即奇数个数,则2~n-1为奇数个数,此时,f(2)与f(n-1)同号,而g(2)与f(2)异号
s= f(n-1)-f(n-2)+f(n-3)-f(n-4)+f(n-5)-f(n-6)+...+f(2) ; g(n)=2*s-g(2)
当n 为偶数时,则1~n为n个数即偶数个数,则2~n-1为偶数个数,此时,f(2)与f(n-1)异号,而g(2)与f(2)异号
s= f(n-1)-f(n-2)+f(n-3)-f(n-4)+f(n-5)-f(n-6)+...-f(2) ; g(n)=2*s+g(2)
f(n)=2^(n-1),所以我们能进一步算出s的表达式:
前提:f(n)-f(n-1)=2^(n-1)-2^(n-2)=2^(n-2)
(1)当n 为奇数时,则1~n为n个数即奇数个数,则2~n-1为奇数个数,所以,3~n-1则为偶数个,此时:
s=(f(n-1)-f(n-2))+(f(n-3)-f(n-4))+...+(f(4)-f(3))+f(2)
=(2^(n-2)-2^(n-3))+(2^(n-3)-2^(n-4))+...+(2^4-2^3)+2^1
=(2^(n-3)+2^(n-5)+...+2^3)+2
=[等比数列求和]+2
易计算得:此等比数列,共(n-3)/2项,首项为2^3=8,公比为2^2=4,则,
s=(2^n+4)/3
(2)当n 为偶数时,则1~n为n个数即偶数个数,则2~n-1为偶数个数,此时:
s=(f(n-1)-f(n-2))+(f(n-3)-f(n-4))+...+(f(3)-f(2))
=(2^(n-2)-2^(n-3))+(2^(n-3)-2^(n-4))+...+(2^3-2^2)
=2^(n-3)+2^(n-5)+...+2^2
=[等比数列求和]
易计算得:此等比数列,共(n-2)/2项,首项为2^2=4,公比为2^2=4,则,
s=(2^n-4)/3
综上所述,易得,总共的方案种数:
(1)当n为奇数时,为2^n-2
(2)当n为偶数时,为2^n+2
这样算出最终结果后,在进行编程实现就容易多了,而且效率也大大提高了(我眼泪都快出来了)......
针对此算法,我的代码如下:
import java.util.Scanner;
import java.math.BigInteger;
接上:问题到这里算解决了,呵呵,其实远远不够,其实问题的原版是n最高能测试到n=10^19不出问题才行(我要哭了)
我不得不说,我黔驴技穷了......
算了,我不得不请教了我们宿舍的某位fudq学长,他给出了一个C++算法,传说中他不会java,说使用了什么矩阵倍增的方法
我晕,我完全看不懂啊......
我把代码贴出来,大家看看,如果有弄明白这算法什么意思的一定要通知我哈:
//特别声明,这个算法原创属于付德强学长,任何非学术研究方面的引用、转载请务必经过他本人同意
#include<iostream>
using namespace std;
#define LL __int64
const int N=5;
const LL M=1000000007;
#define MEM(a) (memset((a),0,sizeof(a)))
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。