1.题目描述![在这里插入图片描述](https://img-blog.csdnimg.cn/073ce031838143a7b7b94e701d33c013.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAY2hhc2VfX3lvdW5n,size_20,color_FFFFFF,t_70,g_se,x_16)
2.输入输出样例![在这里插入图片描述](https://img-blog.csdnimg.cn/e6f937d01819487c8a4488a6dd5c29ad.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAY2hhc2VfX3lvdW5n,size_20,color_FFFFFF,t_70,g_se,x_16)
3.解题思路
很明显,这是一个dfs进行暴力搜索的题,但只使用DFS很容易超时,所以要进行剪枝,即为记忆化搜索。同时,定义状态dp[x][y][num][maxv]。这代表第x行第y列,此时的获得了num个宝物,宝物中的最大价值为maxv。状态为1表示一种方案,状态为0表示不是一种方案。
4.源代码
#include<bits/stdc++.h>
#define N 1000000007
using namespace std;
int n,m,k;
int mapvalue[51][51];
int dp[55][55][15][15];//动态规划路径
int dfs(int x,int y,int num,int maxv){
//判断路径有没走过
if(dp[x][y][num][maxv+1]!=-1)
return dp[x][y][num][maxv+1]; //走过就用统计过的路径(“记忆”的部分)
if(x==n&&y==m){ //走到了右下角
//分拿走或者不拿走右下角那个宝藏,都是一种方案
if(num==k||(num==k-1&&maxv<mapvalue[x][y]))
return dp[x][y][num][maxv+1]=1;
else return dp[x][y][num][maxv+1]=0;// 否则失败
}
//统计路径方案
long long s=0;
//向下深搜,分取或者不取这个宝物,由宝物价值判断
if(x+1<=n){ //向下控制不出界限
if(maxv<mapvalue[x][y])
s+=dfs(x+1,y,num+1,mapvalue[x][y]);
s+=dfs(x+1,y,num,maxv);//也可以不取
}
//向右深搜 分取或者不取这个宝物,由宝物价值判断
if(y+1<=m){ //向下控制不出界
if(maxv<mapvalue[x][y])
s+=dfs(x,y+1,num+1,mapvalue[x][y]);
s+=dfs(x,y+1,num,maxv);//也可以不取
}
return dp[x][y][num][maxv+1]=s%N;
}
int main(){
int i,j;
cin>>n>>m>>k;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++){
cin>>mapvalue[i][j];
}
memset(dp,-1,sizeof(dp)); //注意将dp数组初始化为-1,因为宝物价值有可能是0
dfs(1,1,0,-1);
cout<<dp[1][1][0][0];
return 0; }
5.总结
注意不能直接进行FS,否则会超时,要进行记忆化。同时,动态规划这一块,没怎么学过,要加强