题目描述
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 取模的结果。
思路:
采用动态规划策略,用
X
[
i
]
[
j
]
X[i][j]
X[i][j]表示第i行第j列的宝物的价值。
d
p
[
i
]
[
j
]
[
x
]
[
y
]
dp[i][j][x][y]
dp[i][j][x][y]表示小明走到了
[
i
]
[
j
]
[i][j]
[i][j]取了
x
x
x件物品且最大价值小于
y
y
y的策略数。
考虑递推关系,只能从
[
i
−
1
]
[
j
]
和
[
i
]
[
j
−
1
]
[i-1][j]和[i][j-1]
[i−1][j]和[i][j−1]走到
[
i
]
[
j
]
[i][j]
[i][j],小明可以不取
X
[
i
]
[
j
]
X[i][j]
X[i][j]也可以取
X
[
i
]
[
j
]
X[i][j]
X[i][j],得
d
p
[
i
]
[
j
]
[
x
]
[
y
]
dp[i][j][x][y]
dp[i][j][x][y]状态转移方程如下所示:
当
y
<
=
X
[
i
]
[
j
]
y<=X[i][j]
y<=X[i][j]时,不能取
X
[
i
]
[
j
]
X[i][j]
X[i][j](由dp的定义可得)则
d
p
[
i
]
[
j
]
[
x
]
[
y
]
=
d
p
[
i
−
1
]
[
j
]
[
x
]
[
y
]
+
d
p
[
i
]
[
j
−
1
]
[
x
]
[
y
]
dp[i][j][x][y]=dp[i-1][j][x][y]+dp[i][j-1][x][y]
dp[i][j][x][y]=dp[i−1][j][x][y]+dp[i][j−1][x][y]
当
y
>
X
[
i
]
[
j
]
y>X[i][j]
y>X[i][j]时,此时可以取也可以不取,那么有四部分组成:
n
u
m
1
=
d
p
[
i
−
1
]
[
j
]
[
x
]
[
y
]
+
d
p
[
i
]
[
j
−
1
]
[
x
]
[
y
]
]
(
不
取
X
[
i
]
[
j
]
)
n
u
m
2
=
d
p
[
i
−
1
]
[
j
]
[
x
−
1
]
[
X
[
i
]
[
j
]
]
+
d
p
[
i
]
[
j
−
1
]
[
x
−
1
]
[
X
[
i
]
[
j
]
]
(
取
X
[
i
]
[
j
]
)
d
p
[
i
]
[
j
]
[
x
]
[
y
]
=
n
u
m
1
+
n
u
m
2
num1=dp[i-1][j][x][y]+dp[i][j-1][x][y]] \ \ \ \ \ (不取X[i][j])\\num2=dp[i-1][j][x-1][X[i][j]]+dp[i][j-1][x-1][X[i][j]]\ \ \ \ \ (取X[i][j])\\ dp[i][j][x][y]=num1+num2
num1=dp[i−1][j][x][y]+dp[i][j−1][x][y]] (不取X[i][j])num2=dp[i−1][j][x−1][X[i][j]]+dp[i][j−1][x−1][X[i][j]] (取X[i][j])dp[i][j][x][y]=num1+num2
初始条件,对于
d
p
[
0
]
[
0
]
[
x
]
[
y
]
dp[0][0][x][y]
dp[0][0][x][y] 当x==0时,应当为1(取0个只有一种方案);
x
=
1
&
y
>
X
[
0
]
[
0
]
x=1 \& y > X[0][0]
x=1&y>X[0][0]时应当为1。其余情况均为0.
Python代码如下(相同的代码,C++4ms跑完,Python121ms,只能说确实不适合用来刷算法题很容易就超时了)
n,m,k = map(int,input().strip().split())
X = [[0]+list(map(int,input().strip().split()))for i in range(0, n)]
X.insert(0,[0 for i in range(0,m+1)])
mod = 1000000007
# dp[i][j][k][v] 表示从00走到ij 取了K件物品 最大价值小于等于v的方案数
dp = [[[[0 for x in range(0, 14)]for t in range(0, k+1)]for j in range(0, m+1)]for i in range(0, n+1)]
for i in range(1,n+1):
for j in range(1,m+1):
# 取了x个
for x in range(0,k+1):
# 最大价值为y
for y in range(0,14):
if i==1 and j ==1:
if x==0 or (x==1 and y > X[i][j]):
dp[i][j][x][y]=1
else:
temp = 0
if k!=0 and y > X[i][j]:
temp = temp+dp[i-1][j][x-1][X[i][j]]+dp[i][j-1][x-1][X[i][j]]
temp = temp+dp[i-1][j][x][y]+dp[i][j-1][x][y]
dp[i][j][x][y] = temp%mod
print(dp[n][m][k][13])