[蓝桥杯][2014年第五届真题]地宫取宝

摘花生+LIS(要取得当前格子的物品,这个物品必须比当前所拥有的物品都大,所以物品的重量严格递增)的结合题。

状态表示:(f(i,j,k,c)):当前到达((i,j))位置,已经取了(k)件物品,且最后一件物品的重量为(c)

状态转移:((i,j))可以从((i-1,j))抵达,也可以从((i,j-1))抵达,抵达((i,j))后可考虑选或不选当前位置上的物品,选的话则需满足上一件物品的重量严格小于当前物品的重量。

[f(i,j,k,c)+=f(i,j-1,k,c); \ f(i,j,k,c)+=f(i-1,j,k,c); \ f(i,j,k,c)+=sum_{0 le w < c} f(i,j-1,k-1,w); \ f(i,j,k,c)+=sum_{0 le w < c} f(i-1,j,k-1,w); ]

边界:

[f(1,1,0,0)=1; \ f(1,1,1,g[1][1])=1; ]

注意点

  1. 由于体积的范围为(0 le C_i le 12),我们将体积做加一处理,则体积的范围变成(1 le C_i le 13),这样第四维下标为(0)时可表示当前已选物品的最大体积为(0),即没有选任何物品,为边界状态。
  2. 如果不用体积来记录上一件选择的物品而使用下标来记录的话,则需要五维来表示状态,显然用体积更优。
const int N=55;
int g[N][N];
int f[N][N][15][15];
int n,m,k,c;

int main()
{
    cin>>n>>m>>k;

    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>g[i][j],g[i][j]++,c=max(c,g[i][j]);

    f[1][1][0][0]=1;
    f[1][1][1][g[1][1]]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int u=0;u<=k;u++)
                for(int v=0;v<=c;v++)
                {
                    int &fval=f[i][j][u][v];
                    fval=(fval+f[i-1][j][u][v])%mod;
                    fval=(fval+f[i][j-1][u][v])%mod;
                    if(u && v == g[i][j])
                    {
                        for(int w=0;w<g[i][j];w++)
                        {
                            fval=(fval+f[i-1][j][u-1][w])%mod;
                            fval=(fval+f[i][j-1][u-1][w])%mod;
                        }
                    }
                    
                }
            
     
    int res=0;           
    for(int i=1;i<=c;i++) res=(res+f[n][m][k][i])%mod;
    cout<<res<<endl;
     
    //system("pause");
    return 0;
}
原文地址:https://www.cnblogs.com/fxh0707/p/14565544.html