问题描述
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
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 取模的结果。
样例输入1
2 2 2
1 2
2 1
样例输出1
2
样例输入2
2 3 2
1 2 3
2 1 5
样例输出2
14
解题思路
参考思路
1、依照题意,小明每走一步都与之前的举动有关,我们要做的就是一直往下走,走不通了就掉头,换一条路再往下走,可以很自然的想到使用深搜。
2、仅仅使用深度搜索的方法时存在大量重复计算,并且结果超时,因此需要使用数组保存路径值,重复遍历时直接传值。根据题意,每个格子的值与格子横纵坐标,最大价值及获得宝贝数有关,因此用一个四维数组来表示。
3、根据题意,列出其状态转移方程:
其中i,j表示格子位置,k表示该格子获得了k件宝贝,v表示此时经过路径中,最大值为v。初始情况下k=0,v=-1(v值取值范围为0~12,为了加以区分)。d(i,j,k,v)表示从原点开始达到第(i,j)点,手握k件宝物并且最大价值为v时可以走的路径。
注解:
当小明刚到达(i,j)时会面临两种情况,第一,此格宝物价值高于当前最高价值,小明可以选择捡或不捡;第二,此格宝物价值不高于当前价值,小明不能捡。
同时小明下一步可能走的地点为(i+1,j)或者(i,j+1),因此小明到达下一格时会有6种情况。
反过来说,小明在(i,j)所可能的路径即为这六种情况的路径之和。
4、在遍历的众多过程中,可能存在有一种或多种方式不能得到符合要求的答案,也就是d(i,j,k,v)=0,因此为了区分,初始值设为d=-1。
5、宝物价值初始值设为了-1,为了防止越界,对其下标后移一位。
6、递归至最后一步开始时,符合要求的情况有两种:
第一、此时已有k件宝物;
第二、此时已有k-1件宝物,且最后一个方格的宝物价值大于已拥有的最大值。
PS:该答案可能很大,在取模的同时选择long long更加稳妥。
#include<iostream>
#include<cstring>
using namespace std;
#define MOD %1000000007
int n,m,num;
int map[60][60];
int d[60][60][13][13];
long long dfs(long long i,long long j,long long k,long long v)
{
long long s=0;
if(d[i][j][k][v+1]!=-1) return d[i][j][k][v+1]; //若该值已发生改变,则不再次计算
if(i==n&&j==m) //已到达终点
{
if(k==num||(k==num-1&&v<map[i][j])) //如果此时已经拥有K个值或者已经有K-1个值且最后一个值大于已有最大值 ,即存在符合要求的答案
d[i][j][k][v+1]=1;
else
d[i][j][k][v+1]=0;
return d[i][j][k][v+1];
}
else{
if(v<map[i][j])//若此时最大值小于该点原始值
{
if(i+1<=n)
s=(s+dfs(i+1,j,k+1,map[i][j])MOD+dfs(i+1,j,k,v)MOD)MOD;
if(j+1<=m)
s=(s+dfs(i,j+1,k+1,map[i][j])MOD+dfs(i,j+1,k,v)MOD)MOD;
}
else {
if(i+1<=n)
s=(s+dfs(i+1,j,k,v)MOD)MOD;
if(j+1<=m)
s=(s+dfs(i,j+1,k,v)MOD)MOD;
}
d[i][j][k][v+1]=s;
return d[i][j][k][v+1];
}
}
int main()
{
cin>>n>>m>>num;
memset(d,-1,sizeof(d));//初始化所有值为-1
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>map[i][j];
dfs(1,1,0,-1);
cout<<d[1][1][0][0];
return 0;
}