AcWing 1212. 地宫取宝
考察:线性DP
思路:
最长上升子序列+01背包+数字三角形的综合
因为需要递增取数,所以必须记录上一个数是什么,从左上角到右下角,必须记录坐标,要求取k个数,必须记录取了几个数.因此需要四维数组
首先f[i][j][t][s]可以从上面和左面走来.到达一个新点,可以考虑取还是不取,取就是由t-1递推来,不取就是t递推来.s代表当前最大数字.如果不取就不变,如果取了说明当前mp[i][j]==s.
初始化是在1,1位置.可以取或者不取f[1][1][1][mp[1][1]] = 1(取),f[1][1][0][0]是不取.但是注意权值也能取到0,而不取的情况是任何情况都可以取到的,所以可以将权值全部左移一位.这样就不用处理边界问题.
注意:第4层循环必须从s=0开始,因为存在不取的情况.
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 const int N = 55,mod = 1000000007; 5 int f[N][N][15][15],mp[N][N];//x,y,取了多少件,取后的最大 6 int main() 7 { 8 int n,m,k,ans =0; 9 scanf("%d%d%d",&n,&m,&k); 10 for(int i=1;i<=n;i++) 11 for(int j=1;j<=m;j++) 12 scanf("%d",&mp[i][j]),mp[i][j]++;//处理边界情况,因为0属于范围内,而1 1 0 0可以推导任意情况 13 f[1][1][0][0] = 1;//如果不加1就是取的时候取不到什么都不取的情况 14 f[1][1][1][mp[1][1]] = 1; 15 for(int i=1;i<=n;i++) 16 for(int j=1;j<=m;j++) 17 for(int t=0;t<=k&&i+j>2;t++) 18 for(int s=0;s<=13;s++)//s=0对应什么都不取的情况 19 {//所以不+1,就需要特判s==0是拿了还是没拿 20 if(!s&&t>1) continue; 21 int& v = f[i][j][t][s]; 22 v = (v+f[i-1][j][t][s])%mod; 23 v = (v+f[i][j-1][t][s])%mod; 24 if(mp[i][j]==s&&t) 25 { 26 for(int a=0;a<s;a++) 27 { 28 v = (v+f[i-1][j][t-1][a])%mod; 29 v = (v+f[i][j-1][t-1][a])%mod; 30 } 31 } 32 } 33 for(int i=1;i<=13;i++) ans = (ans+f[n][m][k][i])%mod; 34 printf("%d\n",ans); 35 return 0; 36 }