蓝桥杯历届试题 地宫取宝 dp or 记忆化搜索

 2023-09-11 阅读 16 评论 0

摘要:问题描述   X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。  地宫的入口在左上角,出口在右下角。  小明被带到地宫的入口,国王要求他只能向右或向下行走。  走过某个格子时,如果那个格子中的宝贝价
问题描述
  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会超时,可以dp或者记忆化搜索....理解可以...自己写可能就....gg了...
这样的话,感觉还是记忆化搜索更萌一些,因为不用考虑那么多边界...
思路见代码.
dp:
/*
蓝桥杯历届试题地宫寻宝dp
状态:dp[i][j][num][val] 表示从起点(1, 1)走到(i, j), 已经取了num个宝物,最大价值是val 的方案数。
初态:dp[1][1][0][0] = 1; dp[1][1][1][mp[1][1]] = 1;
转移方程:由上方或者左方的格子转移而来,详见代码;
*/#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;#define mod 1000000007
int dp[55][55][15][15];
int mp[55][55];int main() {int n, m, k;while(~scanf("%d%d%d", &n, &m, &k)) {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) {scanf("%d", &mp[i][j]);}}memset(dp, 0, sizeof(dp));dp[1][1][0][0] = 1;dp[1][1][1][mp[1][1]] = 1;for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) {dp[i][j][0][0] += (dp[i-1][j][0][0] + dp[i][j-1][0][0]);dp[i][j][0][0] %= mod;for (int num=1; num<=k; ++num) {for (int val=0; val<=12; ++val) {dp[i][j][num][val] += (dp[i-1][j][num][val] + dp[i][j-1][num][val]);dp[i][j][num][val] %= mod;}if (num == 1) {dp[i][j][1][mp[i][j]] += dp[i-1][j][0][0];dp[i][j][1][mp[i][j]] %= mod;dp[i][j][1][mp[i][j]] += dp[i][j-1][0][0];dp[i][j][1][mp[i][j]] %= mod;}else {for (int t=0; t<mp[i][j]; ++t) {dp[i][j][num][mp[i][j]] += dp[i-1][j][num-1][t];dp[i][j][num][mp[i][j]] %= mod;dp[i][j][num][mp[i][j]] += dp[i][j-1][num-1][t];dp[i][j][num][mp[i][j]] %= mod;}}}}}int ans = 0;for (int i=0; i<=12; ++i) {ans += dp[n][m][k][i];ans %= mod;}printf("%d\n", ans);}return 0;
}

记忆化搜索:

 

/*
蓝桥杯历届试题 地宫取宝dp[i][j][num][k] 表示到位置(i, j)时, 取了第num个宝藏,最大宝藏值是k时,
能到终点的路线方案数。dfs超时。
记忆化搜索...
*/#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define mod 1000000007int dp[55][55][15][15];
int n, m, k;
int mp[55][55];int dfs(int nowx, int nowy, int cnt, int nowMax) {if (dp[nowx][nowy][cnt][nowMax+1] != -1) {return dp[nowx][nowy][cnt][nowMax+1];}int ans = 0;if (nowx == n-1 && nowy == m-1) {if (mp[nowx][nowy] > nowMax) {if (cnt == k || cnt == k-1)ans++;ans %= mod;}else if (cnt == k) ans++;ans %= mod;return dp[nowx][nowy][cnt][nowMax+1] = ans;}if (nowx+1 < n) {if (mp[nowx][nowy] > nowMax) {ans += dfs(nowx+1, nowy, cnt+1, mp[nowx][nowy]);ans %= mod;}ans += dfs(nowx+1, nowy, cnt, nowMax);ans %= mod;}if (nowy+1 < m) {if (mp[nowx][nowy] > nowMax) {ans += dfs(nowx, nowy+1, cnt+1, mp[nowx][nowy]);ans %= mod;}ans += dfs(nowx, nowy+1, cnt, nowMax);ans %= mod;}return dp[nowx][nowy][cnt][nowMax+1] = ans;
}int main() {while(~scanf("%d%d%d", &n, &m, &k)) {memset(dp, -1, sizeof(dp));for (int i=0; i<n; ++i) {for (int j=0; j<m; ++j) {scanf("%d", &mp[i][j]);}}int ans = dfs(0, 0, 0, -1);printf("%d\n", ans);}return 0;
}

 

  

蓝桥杯上午还是下午。 

转载于:https://www.cnblogs.com/icode-girl/p/5522669.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/3/45506.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息