[Bzoj5359][Lydsy1805月赛]寻宝游戏(dp)

Posted lzdhydzzh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Bzoj5359][Lydsy1805月赛]寻宝游戏(dp)相关的知识,希望对你有一定的参考价值。

5359: [Lydsy1805月赛]寻宝游戏


 

Time Limit: 2 Sec  Memory Limit: 512 MB
Submit: 71  Solved: 19
[Submit][Status][Discuss]

Description


 

Input


 

 

Output


 

 

Sample Input


 

 

Sample Output


 

 

HINT


 

 

Source


 

鸣谢claris提供

 

分析:


dp状态定义很重要,很明显是选一条路径,其中有t个不选,从路径外选t个。
如果k = 0,就是做一遍O(nm)的经典dp
k > 0  :定义状态f[i][j][k][l],表示已考虑完以(1,1)为左上角,(i,j)为右下角的矩形,一条(1,1)到(i,j)的路径中有k个点不选,从外面选了l个点的最大价值。
预处理出g[i][j][k]((i,j + 1)~(i,m)中前k大之和),h[i][j][k] ((i + 1,j) ~(n,j)中前k大和),复杂度O(n^3logn)
转移起来就很简单了(记录每个点权值为s[i][j]):
f[i][j][k][l]  +  g[i][j][x] + s[i + 1][j] ----> f[i+1][j][k][l + x] (从右选了前x大,往下走)
f[i][j][k][l]  +  g[i][j][x] ----> f[i+1][j][k + 1][l + x] (从右选了前x大,往下走,且舍弃s[i + 1][j])
f[i][j][k][l]  +  h[i][j][x] + s[i][j + 1] ----> f[i][j + 1][k][l + x] (从下选了前x大,往右走)
f[i][j][k][l]  +  h[i][j][x] ----> f[i][j + 1][k + 1][l + x] (从下选了前x大,往右走,且舍弃s[i][j + 1])
初始化f[1][1][0][0] = s[1][1],f[1][1][1][0] = 0。就可以在O(n ^ 2k^3)转移了
最后答案就为max(f[n][m][t][t]),t∈[0,K]
所以说dp定义状态比转移关键呢

AC代码:


 

# include <iostream>
# include <cstdio>
# include <cstring>
# include <algorithm>
using namespace std;
int f[52][52][22][22],a[52],b[52],s[52][52],g[52][52][52],h[52][52][52],n,m,K,dt;
bool cmp(int x,int y){return x > y;}
void init()
{
    memset(g,0,sizeof g);
    memset(h,0,sizeof h);
    for(int i = 1;i <= n;i++)
    {
        dt = 0;
        for(int j = m;j >= 1;j--)
        {
              sort(a + 1,a + dt + 1,cmp);
              for(int k = 1;k <= dt;k++)b[k] = b[k - 1] + a[k],g[i][j][k] = b[k];
            a[++dt] = s[i][j];
        }
    }
    for(int j = 1;j <= m;j++)
    {
        dt = 0;
        for(int i = n;i >= 1;i--)
        {
              sort(a + 1,a + dt + 1,cmp);
              for(int k = 1;k <= dt;k++)b[k] = b[k - 1] + a[k],h[i][j][k] = b[k];
            a[++dt] = s[i][j];
        }
    }
    memset(f,0x80,sizeof f);
    f[1][1][0][0] = s[1][1];
    f[1][1][1][0] = 0;
}
int main()
{
    int Case;scanf("%d",&Case);
    while(Case--)
    {
        scanf("%d %d %d",&n,&m,&K);
        for(int i = 1;i <= n;i++)
         for(int j = 1;j <= m;j++)
         scanf("%d",&s[i][j]);
         init();
        for(int i = 1;i <= n;i++)
         for(int j = 1;j <= m;j++)
          for(int k = 0;k <= K;k++)
           for(int l = 0;l <= K;l++)
           {
                for(int t = 0;t <= min(K - l,m - j);t++)
                f[i + 1][j][k][l + t] = max(f[i + 1][j][k][l + t],f[i][j][k][l] + s[i + 1][j] + g[i][j][t]),
                f[i + 1][j][k + 1][l + t] = max(f[i + 1][j][k + 1][l + t],f[i][j][k][l] + g[i][j][t]);
                for(int t = 0;t <= min(K - l,n - i);t++)
                f[i][j + 1][k][l + t] = max(f[i][j + 1][k][l + t],f[i][j][k][l] + s[i][j + 1] + h[i][j][t]),
                f[i][j + 1][k + 1][l + t] = max(f[i][j + 1][k + 1][l + t],f[i][j][k][l] + h[i][j][t]);
           }
        int ans = 0;
        for(int i = 0;i <= K;i++)ans = max(ans,f[n][m][i][i]);
        printf("%d\n",ans);
    }
}

 

 

 

以上是关于[Bzoj5359][Lydsy1805月赛]寻宝游戏(dp)的主要内容,如果未能解决你的问题,请参考以下文章

[Lydsy1805月赛] quailty 算法

bzoj 5091: [Lydsy0711月赛]摘苹果

bzoj月赛1805

BZOJ4952lydsy七月月赛 E 二分答案

bzoj 4921: [Lydsy六月月赛]互质序列

bzoj 5093: [Lydsy1711月赛]图的价值