BZOJ1084: [SCOI2005]最大子矩阵

【传送门:BZOJ1084


简要题意:

  给出n行m列的矩阵,要求选出k个不互相覆盖子矩阵,使得选出的k个子矩阵的和最大,求出和


题解:

  DP

  我的DP方程可能有些麻烦。。

  首先面向数据编程,因为m<=2,所以先把m=1的情况求出来,这个就不用讲了

  然后对于m=2的情况,我们设:

  f[i][k][0]为第i行不选左也不选右,且共有k个子矩阵的最大和

  f[i][k][1]为第i行只选择左边成为子矩阵且共有k个子矩阵的最大和

  f[i][k][2]为第i行只选择右边成为子矩阵且共有k个子矩阵的最大和

  f[i][k][3]为第i行左右边都成为子矩阵,但是并不在同一个子矩阵,且共有k个子矩阵的最大和

  f[i][k][4]为第i行左右边都成为子矩阵,而且在同一个子矩阵,且共有k个子矩阵的最大和

  状态转移不想写了,太烦了。。自行yy吧


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int f1[110],f2[110],a[110],b[110];
int f[110][11][5];
int s1[110][110],s2[110][110];
int s[110][110];
int main()
{
    int n,m,K;
    scanf("%d%d%d",&n,&m,&K);
    int ans=0;
    if(m==1)
    {
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
        {
            for(int j=i;j<=n;j++)
            {
                int d=0;
                for(int k=j;k>=i;k--)
                {
                    d+=a[k];
                    s[i][j]=max(s[i][j],d);
                }
            }
        }
        memset(f,0,sizeof(f));
        for(int k=1;k<=K;k++)
        {
            for(int i=1;i<=n;i++)
            {
                for(int j=0;j<i;j++)
                {
                    f[i][k][0]=max(f[i][k][0],f[j][k-1][0]+s[j+1][i]);
                    ans=max(ans,f[i][k][0]);
                }
            }
        }
    }
    else
    {
        memset(f,-63,sizeof(f));
        for(int i=0;i<=n;i++) for(int k=0;k<=K;k++) f[i][k][0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i],&b[i]);
            for(int k=1;k<=K;k++)
            {
                //不取
                f[i][k][0]=max(f[i-1][k][0],max(f[i-1][k][1],max(f[i-1][k][2],max(f[i-1][k][3],f[i-1][k][4]))));
                //只取左
                f[i][k][1]=max(max(f[i-1][k][1],f[i-1][k][3]),max(f[i-1][k-1][0],max(f[i-1][k-1][2],f[i-1][k-1][4])))+a[i];
                //只取右
                f[i][k][2]=max(max(f[i-1][k][2],f[i-1][k][3]),max(f[i-1][k-1][0],max(f[i-1][k-1][1],f[i-1][k-1][4])))+b[i];
                //左右都取,但左右两边都不在一个子矩阵内
                f[i][k][3]=max(f[i-1][k][3],max(f[i-1][k-1][1],f[i-1][k-1][2]))+a[i]+b[i];
                if(k>=2) f[i][k][3]=max(f[i][k][3],max(f[i-1][k-2][0],f[i-1][k-2][4])+a[i]+b[i]);
                //左右都取,但左右两边都在一个子矩阵内
                f[i][k][4]=max(f[i-1][k-1][0],max(f[i-1][k-1][1],max(f[i-1][k-1][2],max(f[i-1][k-1][3],f[i-1][k][4]))))+a[i]+b[i];
                ans=max(ans,max(f[i][k][0],max(f[i][k][1],max(f[i][k][2],max(f[i][k][3],f[i][k][4])))));
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-04-09 16:15  Star_Feel  阅读(201)  评论(0编辑  收藏  举报