题目描述
原题链接:AcWing 1212.地宫取宝
解题思路
1.分析时间复杂度
题目中说明:
1
≤
n
,
m
≤
50
1\le n,m \le50
1≤n,m≤50,
1
≤
k
≤
12
1 \le k \le 12
1≤k≤12,
0
≤
C
i
≤
12
0 \le C_i \le 12
0≤Ci≤12,
由于
50
∗
50
∗
12
∗
13
≈
4
∗
1
0
5
<
1
0
8
50*50*12*13 \approx 4*10^5 \lt 10^8
50∗50∗12∗13≈4∗105<108,
因此本题可以考虑用一个四重循环的dp解决。
2.闫氏dp分析
3.一些小问题
(1)关于初始化:
刚开始时小明在 ( 1 , 1 ) (1,1) (1,1)的位置,这个时候就有取 ( 1 , 1 ) (1,1) (1,1)这个位置的宝贝和不取的选择。
如果不取:那么 f [ 1 ] [ 1 ] [ 0 ] [ − 1 ] = 1 f[1][1][0][-1]=1 f[1][1][0][−1]=1,这里之所以让 c = − 1 c=-1 c=−1,是因为 k = 0 k=0 k=0时,小明没有取任何宝物,所以此时 c c c应该比最小的宝贝的价值小,也就是比0小。这样如果下一个宝贝的价值为0的话才能取到,否则如果此时 c = 0 c=0 c=0,那么下一个宝贝的价值如果为0就取不到。
如果取:那么 f [ 1 ] [ 1 ] [ 1 ] [ w [ 1 ] [ 1 ] ] = 1 f[1][1][1][w[1][1]]=1 f[1][1][1][w[1][1]]=1。
(2)关于数组越界
由于-1超过数组的下界,因此对于输入的 w [ i ] [ j ] w[i][j] w[i][j]也要有所处理,将其范围变成 [ 1 , 13 ] [1,13] [1,13],这样宝物的最小价值就为1,可以让0表示比最小价值还小的值。
C++代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 51;
const int P = 1e9+7;
int n,m,k,w[N][N],f[N][N][13][14];
int main()
{
cin >> n >> m >> k;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
{
cin >> w[i][j];
w[i][j]++;
}
f[1][1][0][0] = 1;
f[1][1][1][w[1][1]] = 1;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if(i == 1 && j == 1) continue;
for(int K = 0; K <= k; K++)
{
for(int c = 0; c <= 13; c++) #从0开始是因为有一种方案可能一直都没有取宝贝
{
// 不取
f[i][j][K][c] = (f[i-1][j][K][c] + f[i][j-1][K][c]) % P;
if(K > 0 && c == w[i][j]) // 取
{
for(int C = 0; C < c; C++)
{
f[i][j][K][c] = (f[i-1][j][K-1][C] + f[i][j][K][c]) % P;
f[i][j][K][c] = (f[i][j-1][K-1][C] + f[i][j][K][c]) % P;
}
}
}
}
}
}
int res = 0;
for(int i = 0; i <= 13; i++)
{
res = (res + f[n][m][k][i]) % P;
}
cout << res;
}