题解 P1464 【Function】

· · 题解

本弱驹代码,大神们见笑了!

这题目刚开始傻傻地按照题意模拟递归,但是残忍的TLE告诉了我,这题必须用记忆化。也就是说,我们先按照题意把递归的内容写出来,然后把每次0~20以内的答案记录下来,下一次递归时如果rpt(x,y,z)有记录就直接输出就行啦,能省去大量的时间。另外有个细节值得注意(我就是因为这个错了好几次QAQ),良心(bian tai)的出题人会在输入中弄几个负数出来,这样的话你一开始的判断语句如果只写if(f[x][y][z])就炸了(因为不能访问数组负数下标啊呵呵呵),因此加一个特判就行了。

//注:百度“记忆化搜索”

记忆化搜索:算法上依然是搜索的流程,但是搜索到的一些解用动态规划的那种思想和模式作一些保存。

一般说来,动态规划总要遍历所有的状态,而搜索可以排除一些无效状态。

更重要的是搜索还可以剪枝,可能剪去大量不必要的状态,因此在空间开销上往往比动态规划要低很多。

记忆化算法在求解的时候还是按着自顶向下的顺序,但是每求解一个状态,就将它的解保存下来,

以后再次遇到这个状态的时候,就不必重新求解了。

这种方法综合了搜索和动态规划两方面的优点,因而还是很有实用价值的。

下面上代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll rpt[25][25][25];
ll w(ll a,ll b,ll c)
{
    if(a<=0||b<=0||c<=0) return 1;
    else if(rpt[a][b][c]!=0) return rpt[a][b][c];
    else if(a>20||b>20||c>20) rpt[a][b][c]=w(20,20,20);
    else if(a<b&&b<c) rpt[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
    else rpt[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 rpt[a][b][c];
}
int main()
{
    ll a,b,c;
    while(scanf("%lld%lld%lld",&a,&b,&c)==3){
        memset(rpt,0,sizeof(rpt));
        if(a==-1&&b==-1&&c==-1) break;
        printf("w(%lld, %lld, %lld) = ",a,b,c);
        if(a>20) a=21;
        if(b>20) b=21;
        if(c>20) c=21;
        printf("%lld\n",w(a,b,c));
    }
    return 0;
}