(记忆化递归)地宫取宝
X 国王有一个地宫宝库。是 n x m 个格子的矩阵。
每个格子放一件宝贝。每个宝贝贴着价值标签。地宫的入口在左上角,出口在右下角。
小明被带到地宫的入口,国王要求他只能向右或向下行走。走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。
请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。
【数据格式】
输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值要求输出一个整数,表示正好取k个宝贝的行动方案数。
该数字可能很大,输出它对 1000000007 取模的结果。
例如
输入:2 2 2
1 2
2 1
输出:2
再例如
输入:2 3 2
1 2 3
2 1 5
输出:14
解法一:暴力dfs
#include <cstdio> #include <string.h> #include <iostream> #include <algorithm> #include <sstream> #include <math.h> using namespace std; const int inf=0x7fffffff; const long long mod=1e9+7; const double PI=acos(-1); bool vis[105]; int a[105][105]; int n,m,k; long long ans; void dfs(int x,int y,int p,int mx){ if(p>k||x>=n||y>=m){ return; } if(x==n-1&&y==m-1){ //到最后一个格子 if(p==k){ //到最后格子前已经取了 k 个物品 ans++; ans=ans%mod; } if(p==k-1&&a[x][y]>mx){ //到最后格子还没有取到 k 个物品,但是最后一个格子的值比此时的最大值大 就可以取最后一个格子取满k个数 ans++; ans=ans%mod; } return; } if(a[x][y]>mx){ //此时的格子价值大于现在的最大值 可以拿该物品 dfs(x+1,y,p+1,a[x][y]); dfs(x,y+1,p+1,a[x][y]); } dfs(x+1,y,p,mx); //不管格子的价值是不是很大 都可以不拿该物品 dfs(x,y+1,p,mx); } int main() { scanf("%d %d %d",&n,&m,&k); for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ scanf("%d",&a[i][j]); } } dfs(0,0,0,-1); //格子的价格可能为 0 所以最初传入最大值-1 才可以更新 cout<<ans; return 0; }
解法二:记忆化递归
可以这么理解:先用暴力递归做出来,然后把它转换为记忆化搜索,即在头查表,在尾写表,表的参数和dfs的参数一致。
然后,就是用一个数组来记录计算过的值
接着,你再在递归函数头部——if (这个数组的值不为初始值) return 这个值;最后,后面的递归返回值里——“数组=”递归返回值。
#include<iostream> #include<string.h> #include<math.h> using namespace std; int n,m,k; int ans; int mod=1e9+7; int a[105][105]; int cache[50][50][20][20]; bool vis[105]; long long dfs(int x,int y,int cot,int mx){ //记忆型递归主要是改开头和结尾 if(cache[x][y][cot][mx+1]!=-1){ //查缓存 return cache[x][y][cot][mx+1]; } long long ans=0; if(x>=n||y>=m||cot>k){ return 0; } if(x==n-1&&y==m-1){ //到最后一个格子 if(cot==k){ //到最后格子前已经取了 k 个物品 ans++; ans=ans%mod; } if(cot==k-1&&a[x][y]>mx){ //到最后格子还没有取到 k 个物品,但是最后一个格子的值比此时的最大值大 就可以取最后一个格子取满k个数 ans++; ans=ans%mod; } return ans; } if(a[x][y]>mx){ ans+=dfs(x+1,y,cot+1,a[x][y]); ans+=dfs(x,y+1,cot+1,a[x][y]); } ans+=dfs(x+1,y,cot,mx); ans+=dfs(x,y+1,cot,mx); cache[x][y][cot][mx+1]=ans%mod; //写缓存 return ans%mod; //添加返回值 } int main(){ cin>>n>>m>>k; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ cin>>a[i][j]; } } memset(cache,-1,sizeof(cache)); cout<<dfs(0,0,0,-1); return 0; }