思路:也是看了后面的题解才理解和学会这个算法,这是一道记忆化搜索的好题,因为题目描述了后面的数会非常大,所以我们不可能每个数字都去进行一次递归,我们可以将已经计算过的数字存储起来,当我们要用到它时,判断它是否已被记录,如果已被记录那么我们就直接返回里面存储的值即可:
上代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll f[25][25][25]; //用一个三维数组来存储,不用把他想得太抽象话,只要把他想象成对应的三位数里面存储的结果即可
bool vis[25][25][25]; //记忆化搜索,如果搜过的数字就将他标记为已搜索,然后直接返回里面存储的值即可
ll a,b,c; //三个数字,因为会比较大记得开Longlong
ll mw(ll a,ll b,ll c){ //递归程序
if(a<=0||b<=0||c<=0)return 1; //题目的前两个条件符合的话直接输出即可
if(a>20||b>20||c>20)return mw(20,20,20);
if(vis[a][b][c])return f[a][b][c]; //如果这三位数字被调用过,直接返回即可
if(a<b&&b<c){
f[a][b][c]=mw(a,b,c-1)+mw(a,b-1,c-1)-mw(a,b-1,c);
}else{
f[a][b][c]=mw(a-1,b,c)+mw(a-1,b-1,c)+mw(a-1,b,c-1)-mw(a-1,b-1,c-1);
}
vis[a][b][c]=true; //当前三位数字搜索完了就将他们标记为已搜索
return f[a][b][c]; //返回结果即可
}
int main(){
memset(vis,false,sizeof(vis)); //初始化为false
scanf("%lld %lld %lld",&a,&b,&c); //输出三个数
while(1){
if(a==-1&&b==-1&&c==-1){ //如果满足推出条件就把他推出,否则继续循环输入
break;
}else{
printf("w(%lld, %lld, %lld) = %lld\n",a,b,c,mw(a,b,c)); //输出的时候要注意空格,我被这个格式问题wa了好几发
scanf("%lld %lld %lld",&a,&b,&c);
}
}
return 0;
}