1212 地宫取宝
可真是醉了。
这是记忆化搜索的题目,为了弄懂,又花了不少时间。
记忆化搜索=深搜+动态规划
题目要求的只能向下或者向右,所有只用了两个坐标。
其实取模每次都应该取的,但是居然只在结果取模没爆,就没改。
解题步骤:
题目要求取k个物品,且每次取都不能比之前取过的所有物品的最大值小,可以在路径上选择取或者不取。
设方程:dp[x][y][num][val] =n — 表示(x,y)位置下取了num个物品,当前最大物品的价值为val的情况下,共有n种情况。
(1)考虑到不取也是一种情况,相当于在该位置 +0,所以首先把dp数组初始成 -1,代表没走过当前位置。再考虑如果走到当前位置,数组下标不能为 -1,所以再把所有的maxval值 +1。
(2)给深搜设置出口,一定是走到右下角的位置,即(x=n && y=m),到出口了进行判断,有两种可行情况,一种是num=k,已经正好选了k个,最后一个不选;另一种是num=k-1 & 右下角物品的值大于val的值,已经正好选了k-1个,最后一个物品还能被选择。其余情况皆不满足条件。满足条件返回1,代表情况数 +1,不满足条件返回0。
(3)对于每个(x,y)的位置,都可以有两种情况,要么向下,要么向右。每种情况判断一下边界值,以及当前的物品是否可选,可选就选或不选两种情况都放进去递归,不可选就一种放进去递归。
因为深搜是搜到终点后不断向回传递的,就像(3)种的(x,y),是向后或向右的总情况数传递回来,再加到当前的情况数中,所以有了一个sum,累加情况数,最后把得到的结果赋给dp数组。也正是从右下角(终点)向回传递,才有最终的答案是dp[1][1][0][0]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=55;
const int N=15;
int maps[maxn][maxn];
int dp[maxn][maxn][N][N];
int dir[2][2]={
{1,0},{0,1}
};
int n,m,k;
int dfs(int x,int y,int num,int val){
if(dp[x][y][num][val+1]!=-1){
return dp[x][y][num][val+1];
}
if(x==n&&y==m){
if(num==k||(num==k-1&&maps[x][y]>val)){
return 1;
}
return 0;
}
long long sum=0;
for(int i=0;i<2;i++){
int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(xx<=n&&yy<=m){
if(maps[x][y]>val) sum+=dfs(xx,yy,num+1,maps[x][y]);
sum+=dfs(xx,yy,num,val);
}
}
return dp[x][y][num][val+1]=sum%mod;
}
int main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>maps[i][j];
}
}
memset(dp,-1,sizeof(dp));
dfs(1,1,0,-1);
cout<<dp[1][1][0][0];
system("pause");
return 0;
}
1215 小朋友排队
今天晚点补,刚打了牛客的比赛。