传送门
作为一个蒟蒻,递归是搞不懂的,这辈子都搞不懂的
正题开始
作为一个已经将“递归”二字刻在脑门上的递归题,明显是要用递归解决。这不废话吗
递归的规则已经告诉我们了,我们直接照着规则来就行。
递归规则:
-
如果(a le 0) (or) (b le 0) (or) (c le 0)就返回值(1).
-
如果(a>20) (or) (b>20) (or) (c>20)就返回(w(20,20,20))
-
如果(a<b)并且(b<c) 就返回(w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,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))
第(1)条和第(2)条规则很明显是一个边界,每条规则的优先级是从上到下,这个优先级不能错。
还有那只要长了眼就能看到的提示:记忆化搜索。
那记忆化搜索又是怎么一回事呢?
敲黑板
记忆化搜索(Memory search)简称记忆化,是一种用于保留 每次搜索的结果或动态规划的某一进程的一种方式。
记忆化搜索
举一个很好理解的栗子
走迷宫
在走迷宫时,不通的路一般我们会打上一个记号,以免重复的走这条路,达到节省时间的效果。
显然是一个空间换时间
因为你需要用空间来存储记号
这个题也一样,在算已经算过的数据时只需要调用之前运行过的结果就可以了。
而在算没算过的数据时,算完要将结果保存下来,以备时需。
记忆化核心代码:
long long w(long long a,long long b,long long c)
{
if(a<=0||b<=0||c<=0)//下边界
return 1;
if(a>20||b>20||c>20)//上边界
return w(20,20,20);
if(function[a][b][c]!=-1)//判断有没有算过
return function[a][b][c];//算过就直接返回结果
if(a<b&&b<c)//规则3
{
function[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);//记忆化
return function[a][b][c];
}
//前三个规则都不是
function[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 function[a][b][c];
}