题目:
分析:
由题目容易知道使用动态规划来解决,设定一个四维数组 dp[55][55][15][15],此数组用于存放当前的行动方案数量,由题目给出的数据范围可以推测出设定的数组不会使内存爆炸,dp[i][j][k][c]我们定义为到 (i,j) 这个点时,拿到了k件物品,并且当前的物品的最大价值小于c的方案数,那么可以推测出下面几种情况:
-
当mat[i][j] > 目前的最大价值(mat[i][j]表示位于(i,j)坐标的物品的价值)时,也就是说此时如果要取走(i,j)坐标的物品,那么位于(i-1,j)和(i,j-1)坐标的价值肯定小于mat[i][j],那么此时设置一个tmp1
tmp1 = dp[i-1][j][k-1][mat[i][j]] + dp[i][j-1][k-1][mat[i][j]] -
不管mat[i][j]大于当前的最大价值时,也可以选择不取位于(i,j)的物品,当mat[i][j]小于当前的最大价值时,则不能取走(i,j)的物品,所以不管是大于还是小于,都存在不取的这种情况,此时设置一个tmp2
tmp2 = dp[i-1][j][k][c] + dp[i][j-1][k][c]
最后 dp[i][j][k][c] = (tmp1%mod + tmp2%mod)%mod即可得出当前的方案数
最后输出dp[n][m][k][13]
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MOD = 1e9+7;
int mat[55][55];
int dp[55][55][15][15];
int n,m,k,ans;
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&mat[i][j]);
int tmp1,tmp2;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
for(int l=0;l<=k;++l)
for(int c=0;c<=13;++c)
{
tmp1 = 0;
if(i==1&&j==1) //此处表示初始条件
{
if(l==0) dp[i][j][l][c] = 1;
if(l==1&&c>mat[i][j]) dp[i][j][l][c]=1;
continue;
}
if(c>mat[i][j]&&l) tmp1 = dp[i-1][j][l-1][mat[i][j]] + dp[i][j-1][l-1][mat[i][j]];
tmp2 = dp[i-1][j][l][c] + dp[i][j-1][l][c];
dp[i][j][l][c] = (tmp1%MOD+tmp2%MOD)%MOD;
}
printf("%d\n",dp[n][m][k][13]);
return 0;
}