题目:
X 国王有一个地宫宝库,是 n×mn×m 个格子的矩阵,每个格子放一件宝贝,每个宝贝贴着价值标签。
地宫的入口在左上角,出口在右下角。
小明被带到地宫的入口,国王要求他只能向右或向下行走。
走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。
当小明走到出口时,如果他手中的宝贝恰好是 kk 件,则这些宝贝就可以送给小明。
请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这 kk 件宝贝。
输入格式
第一行 33 个整数,n,m,kn,m,k,含义见题目描述。
接下来 nn 行,每行有 mm 个整数 CiCi 用来描述宝库矩阵每个格子的宝贝价值。
输出格式
输出一个整数,表示正好取 kk 个宝贝的行动方案数。
该数字可能很大,输出它对 10000000071000000007 取模的结果。
数据范围
1≤n,m≤501≤n,m≤50,
1≤k≤121≤k≤12,
0≤Ci≤120≤Ci≤12
输入样例1:
2 2 2
1 2
2 1
输出样例1:
2
输入样例2:
2 3 2
1 2 3
2 1 5
输出样例2:
14
个人认为这篇题解很好
https://www.acwing.com/solution/content/7116/
代码:
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MOD 1000000007
#define N 55
#define M 15
int n,m,c;
int a[N][N];
int f[N][N][M][M];//f[坐标][坐标][取的个数][当前最大价值]
int main()
{
cin>>n>>m>>c;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
a[i][j]++;//价值从1开始,才可以将0设为边界
}//dp就是转移方程到原点的方案累加
f[1][1][0][0]=1;//在原点的时候不拿算一种方案,这时候0不算物品
f[1][1][1][a[1][1]]=1;//在原点的时候拿就是一种情况
for(int i=1;i<=n;i++)
{//坐标枚举
for(int j=1;j<=m;j++)
{//个数枚举,此时已经拿了多少个
for(int u=0;u<=c;++u)
{//直接枚举取的价值是多少,反正不会超出价值12
for(int v=0;v<=M;v++)
{//不拿直接从上和从左边转移过来
f[i][j][u][v]=(f[i][j][u][v]+f[i-1][j][u][v])%MOD;
f[i][j][u][v]=(f[i][j][u][v]+f[i][j-1][u][v])%MOD;
if(u>0 && v==a[i][j])//求的就是拿和不拿两种情况的总和
{//如果拿了
for(int k=0;k<a[i][j];k++)
{//拿的话就倒推回去,上一步有可能是0-k-1的任何一个值,因为只要不比k大就行
f[i][j][u][v]=(f[i][j][u][v]+f[i-1][j][u-1][k])%MOD;
f[i][j][u][v]=(f[i][j][u][v]+f[i][j-1][u-1][k])%MOD;
}
}
}
}
}
}
int res=0;
for(int i=1;i<=M;i++)
res=(res+f[n][m][c][i])%MOD;
cout<<res<<endl;
return 0;
}