地宫取宝
题目描述
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 3 2
1 2 3
2 1 5
样例输出
14
解题思路
采用动态规划的方法,首先确定dp数组含义。因为不仅要考量行列信息,还有考量当前手中的宝物数量,同时宝物拿取存在要求,必须当前格子宝物价值比手中所有宝物价值都大才可以取,所以采用四维数组。
dp[i][j][k][w]
表示在当前第i
行第j
列时手中宝物数量为k
,手中宝物的价值不超过w2
情况下的种类数。
边界状态
- 第一行第一列手中宝物数量为0时,种类数为1.
- 第一行第一列手中宝物数量为1时,且手中宝物价值大于第一行第一列的价值种类数为1.
状态转移方程
- 不拿,
dp[i][j][k][w]=dp[i-1][j][k1][w]+dp[i][j-1][k1][w]
- 拿,
dp[i][j][k][w]=dp[i-1][j][k1-1][wealth[i][j]]+dp[i][j-1][k1-1][wealth[i][j]]
,拿当前的第i
行第j
列的宝物的种类数来自(1)上一行k-1
件商品且最大宝物价值不超过当前格子宝物价值的种类数。(2)前一列k-1
件商品且最大宝物价值不超过当前格子宝物价值的种类数。 - 当前
dp[i][j][k][w]
种类为拿当前的宝物种类数和不拿当前宝物的种类数之和。
注意:种类数较大,需要时刻注意取模问题。
代码
import java.util.Scanner;public class Main {static final int MOD = 1000000007;public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int m = scanner.nextInt();int k = scanner.nextInt();//dp[i][j][k][m]---棋盘第i行,第j列上有k件宝物并且宝物最大价值不超过m的种类数//创建棋盘宝物价值数组int[][] wealth=new int[n+1][m+1];for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){wealth[i][j]=scanner.nextInt();}}//创建四维数组并初始化int[][][][] dp=new int[n+1][m+1][k+1][13];for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){for(int k1=0;k1<=k;k1++){for(int w2=0;w2<13;w2++){//边界状态赋值if (i == 1 && j == 1) {//边界状态k1=0 手上没有宝物,不取宝物,则第1行第1列手上宝物为0,最大价值不超过w2的种类数为1//k1=1,w2>wealth[1][1] 在第1行第1列拿取一个宝物,要拿宝物,那么最大价值要超过当前格子的宝物价值,其种类数为1if (k1 == 0 || (k1 == 1 && w2 > wealth[1][1])) {dp[i][j][k1][w2] = 1;}continue;}int num_notake=0;int num_take=0;//拿当前的商品if(k1>0&&w2>wealth[i][j]){num_take=dp[i-1][j][k1-1][wealth[i][j]]%MOD+dp[i][j-1][k1-1][wealth[i][j]] % MOD;num_take%=MOD;}//不取当前商品num_notake=dp[i-1][j][k1][w2]%MOD+dp[i][j-1][k1][w2] % MOD;//这一步很重要,如果不取模,那么结果将会溢出,加数取模后和应该继续取模num_notake%=MOD;dp[i][j][k1][w2]=(num_notake+num_take)%MOD;}}}}System.out.println(dp[n][m][k][12]);}
}