对于一个递归函数w(a,b,c)
如果a<=0 or b<=0 or c<=0就返回值1.
如果a>20 or b>20 or c>20就返回w(20,20,20)
如果a
其它别的情况就返回w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1)
这是个简单的递归函数,但实现起来可能会有些问题。当a,b,c均为15时,调用的次数将非常的多。你要想个办法才行.
/*
absi2011 : 比如 w(30,-1,0)既满足条件1又满足条件2
这种时候我们就按最上面的条件来算
所以答案为1
*/
会有若干行.
并以-1,-1,-1结束.
保证输入的数在-9223372036854775808~9223372036854775807之间
并且是整数
输出格式:输出若干行
格式:
[b]w(a,_b,c)=_你的输出(_代表空格)[/b]
1 1 1 2 2 2 -1 -1 -1
w(1, 1, 1) = 2 w(2, 2, 2) = 4
记忆化搜索
-----------------------------------------------------------------------------分割线-----------------------------------------------------------------------------
好,让我开始吧。
先看题目,看起来很简单诶,直接递归调用不就得了?
正当我开始写时,却发现下面有两行字:
记忆化搜索
等等,记忆化搜索是个什么玩意啊?管他呢,先写完提交上去再说。于是我开开心心地写完了。
提交后,却发现TLE,这是为啥啊?于是我拿起笔算了一下,这个时间复杂度竟然高达a^n,怪不得超时。这时我才开始仔细研究“记忆化搜索”这五个字。
先看看“搜索”,这个肯定所有人都懂啊,就是深度优先搜索的那个搜索啊。那什么叫“记忆化”呢?我想啊想,想到了刚刚提交的超时程序,才发现有很多重复计算的,比如在计算w(1,2,3)和w(2,2,3)时,都需要用到w(1,1,2),如果输入时数满足既需要w(1,2,3),也需要w(2,2,3),那就无异于算了两遍w(1,1,2)。
那么解决方法瞬间就浮现在我眼前了:既然可能会用两遍w(1,1,2)。那在第一遍肯定需要先算一遍,第二次要用的时候,直接用第一次的结果,不就可以了么?
那么问题又来了,第二次要怎么用呢?我想到了一个非常简单的方法:直接用一个数组把算出来的结果储存下来,下次要用的时候先判断是否算过w(1,1,2),如果算过,就直接用好了。这难道不就是所谓的“记忆化”吗?!
有了这个思路,代码就很简单了,我写道:
int w(int a,int b,int c){
if(a<=0||b<=0||c<=0) return 1;
//不解释
if(s[a][b][c]) return s[a][b][c];
//用s[a][b][c]来储存,如果已经计算过一次,就不用再进行计算了
else if(a>20||b>20||c>20) s[a][b][c]=w(20,20,20);
//不解释
else if(a
//把计算结果储存在s数组中
else s[a][b][c]=w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
//同上
return s[a][b][c];
//不解释
}
再提交上去,完美AC,原来传说中的记忆化搜索时这个意思啊!
-----------------------------------------------------------------------------分割线-----------------------------------------------------------------------------
最后附上完整代码:
#include
using namespace std;
int s[21][21][21];
long long int a[1000],b[1000],c[1000];
int a1[1000],b1[1000],c1[1000];
int w(int a,int b,int c){
if(a<=0||b<=0||c<=0) return 1;
if(s[a][b][c]) return s[a][b][c];
else if(a>20||b>20||c>20) s[a][b][c]=w(20,20,20);
else if(a
else s[a][b][c]=w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
return s[a][b][c];
}
int main(){
int result[100];
int i=0;
int j=0;
while(1){
scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
if(a[i]==-1&&b[i]==-1&&c[i]==-1) break;
if(a[i]>21||b[i]>21||c[i]>21) a1[i]=b1[i]=c1[i]=21;
else{
a1[i]=a[i];
b1[i]=b[i];
c1[i]=c[i];
}
result[i]=w(a1[i],b1[i],c1[i]);
i++;
}
for(j=0;j
printf("w(%lld, %lld, %lld) = %d\n",a[j],b[j],c[j],result[j]);
}
return 0;
}