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 }

 

posted @ 2021-02-07 22:20  acmloser  阅读(63)  评论(0编辑  收藏  举报