[蓝桥]地宫取宝(dp, 记忆化搜索)
2016-03-18 15:03
381 查看
问题描述 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
dp,记忆化搜索可以免除一些不必要的计算。记录当前坐标和当前宝物数量还有当前持有最大价值。每次更新前要判断下一步是否满足条件
状态转移方程:
dp(i, j, k, v) = max (
dp(i+1, j, k, v) + dp(i, j+1, k, v) (G(i, j) <= v),
dp(i+1, j, k+1, G(i, j)) + dp(i, j+1, k+1, G(i, j)) + dp(i+1, j, k, v) + dp(i, j+1, k, v) (G(i, j) > v)
)
代码如下:
#include <algorithm> #include <iostream> #include <iomanip> #include <cstring> #include <climits> #include <complex> #include <fstream> #include <cassert> #include <cstdio> #include <bitset> #include <vector> #include <deque> #include <queue> #include <stack> #include <ctime> #include <set> #include <map> #include <cmath> using namespace std; typedef long long ll; const ll maxn = 55; const ll mod = 1000000007; int n, m, kk; ll G[maxn][maxn]; ll dp[maxn][maxn][15][15]; ll dfs(ll i, ll j, ll k, ll v) { if(dp[i][j][k][v+1] != -1) return dp[i][j][k][v+1]; if(i == n - 1 && j == m - 1) { if(k == kk) return dp[n-1][m-1][k][v+1] = 1; else if(k == kk - 1 && G[n-1][m-1] > v) return dp[n-1][m-1][k][v+1] = 1; else return dp[n-1][m-1][k][v+1] = 0; } ll s = 0; if(G[i][j] > v) { if(i + 1 < n) s = ((s + dfs(i+1, j, k+1, G[i][j])) % mod + dfs(i+1, j, k, v) % mod) % mod; if(j + 1 < m) s = ((s + dfs(i, j+1, k+1, G[i][j])) % mod + dfs(i, j+1, k, v) % mod) % mod; } else { if(i + 1 < n) s = (s + dfs(i+1, j, k, v) % mod) % mod; if(j + 1 < m) s = (s + dfs(i, j+1, k, v) % mod) % mod; } return dp[i][j][k][v+1] = s; } int main() { // freopen("in", "r", stdin); while(~scanf("%d %d %d", &n, &m, &kk)) { memset(dp, -1, sizeof(dp)); for(ll i = 0; i < n; i++) { for(ll j = 0; j < m; j++) { scanf("%d", &G[i][j]); } } dfs(0, 0, 0, -1); printf("%I64d\n", dp[0][0][0][0]); } return 0; }
相关文章推荐
- JS实现行选中事件
- Android 的ORM GreenDao
- go源码阅读笔记(math.3)
- CSS之 Px rm rem之区别
- linux的nohup命令的用法
- Linux命令学习总结: file命令
- 2002年 均分纸牌
- ios Tabbar Item 的图标
- Entity Framework 使用注意:Where查询条件中用到的关联实体不需要Include
- android studio 的内存使用分析
- Fatal error: Allowed memory size of xxx bytes exhausted.(tried to allocate xxx bytes)
- TableView性能优化
- (1)java自带软件包javax.crypto的使用方法,对称加密方法和非对称加密方法
- Android常用工具方法
- Java enum的用法详解
- android studio 代码提交及冲突解决
- 2、ExtJs中日期组件value和getValue()取值的区别(转)
- UVa 11988 - Broken Keyboard (a.k.a. Beiju Text) 题解
- msql命令大全
- C/C++宏定义的可变参数