@ 蓝桥杯 练习系统 历届试题 PREV-28
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
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 取模的结果。
测试样例1
Input:
2 2 2
1 2
2 1
Output:
2
测试样例2
Input:
2 3 2
1 2 3
2 1 5
Output:
14
ACcode:
import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.Arrays;
public class Main {
static int n, m, k;
static int[][] map, dp[][];
static final int mod = 1000000007;
public static void main(String[] args) {
InputReader in = new InputReader(System.in, " ");
n = in.nextInt(); m = in.nextInt(); k = in.nextInt();
dp = new int[n + 1][m + 1][13][14];
map = new int[n + 1][m + 1];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
map[i][j] = in.nextInt();
for (int l = 0; l < 13; l++) Arrays.fill(dp[i][j][l], 0, 14, -1);
}
System.out.print(dfs(1, 1, 0, -1));
}
static int dfs(int i, int j, int k, int v) {
if (dp[i][j][k][v + 1] != -1) return dp[i][j][k][v + 1];
int t = 0;
if (i == n && j == m) {
if (k == Main.k || (map[i][j] > v && k == Main.k - 1))
return dp[i][j][k][v + 1] = ++t;
return dp[i][j][k][v + 1] = t;
}
if (i < n) {
if (map[i][j] > v)
t = (t + dfs(i + 1, j, k + 1, map[i][j])) % mod;
t = (t + dfs(i + 1, j, k, v)) % mod;
}
if (j < m) {
if (map[i][j] > v)
t = (t + dfs(i, j + 1, k + 1, map[i][j])) % mod;
t = (t + dfs(i, j + 1, k, v)) % mod;
}
return dp[i][j][k][v + 1] = t % mod;
}
static class InputReader {
BufferedReader read;
StringTokenizer tok;
String delimiters;
InputReader(InputStream in) { this(in, " \n\t\r\f"); }
InputReader(InputStream in, String delimiters) {
this.read = new BufferedReader(new InputStreamReader(in));
this.tok = new StringTokenizer("", this.delimiters = delimiters);
}
String next() {
while (!tok.hasMoreTokens())
try {
tok = new StringTokenizer(read.readLine(), delimiters);
} catch (IOException e) { }
return tok.nextToken();
}
int nextInt() { return Integer.parseInt(next()); }
}
}
如果单看搜索:
static int dfs(int i, int j, int k, int v) {
int t = 0;
if (i == n && j == m) {
if (k == Main.k || (map[i][j] > v && k == Main.k - 1))
return 1;
return 0;
}
if (i < n) {
if (map[i][j] > v)
t = (t + dfs(i + 1, j, k + 1, map[i][j])) % mod;
t = (t + dfs(i + 1, j, k, v)) % mod;
}
if (j < m) {
if (map[i][j] > v)
t = (t + dfs(i, j + 1, k + 1, map[i][j])) % mod;
t = (t + dfs(i, j + 1, k, v)) % mod;
}
return t % mod;
}
这题还是很清晰的
再在此基础上进行记忆化优化搜索优化
d p [ i ] [ j ] [ k ] [ v ] dp[i][j][k][v] dp[i][j][k][v]记录存在几条,行走到 m a p [ i ] [ j ] map[i][j] map[i][j] 已取得 k k k 个宝物,并以 v v v为最小价值的道路,存在即返回,避免重复搜索