蓝桥杯:地宫取宝
标题:地宫取宝
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
错误的写法
/* * CreateTime: 2015-04-06 10:29:05 */ #include <cstdio> const int maxn = 80; int k; int n; int m; int count; int g[maxn][maxn]; int cur_max; void dfs(int i, int j, int step) { if (i > n || j > m || step > k ) { return; } if (step == k) { count++; } if (g[i][j] > cur_max) { int ori_max = cur_max; cur_max = g[i][j]; dfs(i+1, j, step+1); dfs(i, j+1, step+1); cur_max = ori_max; // 回溯 dfs(i+1, j, step); dfs(i, j+1, step); } else { dfs(i+1, j, step); dfs(i, j+1, step); } } int main(void) { cur_max = 0; n = 2; m = 3; k = 2; count = 0; g[1][1] = 1; g[1][2] = 2; g[1][3] = 3; g[2][1] = 2; g[2][2] = 1; g[2][3] = 5; dfs(1, 1, 0); printf("%d\n", count); return 0; }
改进后
#include <cstdio> const int maxn = 80; int k; int n; int m; int count; int g[maxn][maxn]; int cur_max; void dfs(int i, int j, int step) { if (i > n || j > m || step > k ) { return; } if (n == i && m == j) { if (step == k) { count++; } else if (step == k-1) { if (g[i][j] > cur_max) { count++; } } return; } if (g[i][j] > cur_max) { int ori_max = cur_max; cur_max = g[i][j]; dfs(i+1, j, step+1); dfs(i, j+1, step+1); cur_max = ori_max; // 回溯 dfs(i+1, j, step); dfs(i, j+1, step); } else { dfs(i+1, j, step); dfs(i, j+1, step); } } int main(void) { cur_max = 0; n = 2; m = 3; k = 2; count = 0; g[1][1] = 1; g[1][2] = 2; g[1][3] = 3; g[2][1] = 2; g[2][2] = 1; g[2][3] = 5; dfs(1, 1, 0); printf("%d\n", count); return 0; }
再次改进
#include <iostream> using namespace std; const int maxn = 80; int k; int n; int m; long long count; int g[maxn][maxn]; void dfs(int i, int j, int step, int max) { if (i > n || j > m || step > k ) { return; } if (i == n && j == m) { if (step == k) { count++; } else if (step == k-1 && max < g[i][j]) { count++; } } if (g[i][j] > max) { dfs(i+1, j, step+1, g[i][j]); dfs(i, j+1, step+1, g[i][j]); } dfs(i+1, j, step, max); dfs(i, j+1, step, max); } int main(void) { cin >> n >> m >> k; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cin >> g[i][j]; } } dfs(1, 1, 0, -1); cout << count % 1000000007 << endl; return 0; }
用记忆的方法去改进
/* * CreateTime: 2015-04-06 10:29:05 */ #include <iostream> #include <cstring> #include <cstdio> using namespace std; const int maxn = 80; const int mod = 1000000007; int k; int n; int m; int g[maxn][maxn]; int mem[maxn][maxn][15][15]; int dfs(int i, int j, int step, int max) { if (mem[i][j][step][max+1] != -1) { return mem[i][j][step][max+1]; } if (i > n || j > m || step > k ) { return 0; } if (i == n && j == m) { if (step == k) { return mem[i][j][step][max+1] = 1; } else if (step == k-1 && max < g[i][j]) { return mem[i][j][step][max+1] = 1; } } int s = 0; if (g[i][j] > max) { s += dfs(i+1, j, step+1, g[i][j]); s = s % mod; s += dfs(i, j+1, step+1, g[i][j]); s = s % mod; } s += dfs(i+1, j, step, max); s = s % mod; s += dfs(i, j+1, step, max); s = s % mod; return mem[i][j][step][max+1] = s; } int main(void) { memset(mem, -1, sizeof(mem)); cin >> n >> m >> k; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cin >> g[i][j]; } } int s = dfs(1, 1, 0, -1); cout << s % mod << endl; return 0; }