[SCOI2005]最大子矩阵

这是一道神奇的DP。。。矩形可以为空哦~。。。方法好像很多。。。QVQ

 对于暴力的 n^4 做法。。。大佬们肯定都明白。。。蒟蒻就不在赘述了。。。

直接抄袭一段代码。。。

呆码:

#include<iostream>
#include<cstdio>
using namespace std;

int n,m,k,dp[110][110][11],map[110][3],res[110][3],two[110];

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&map[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            res[i][j]=res[i-1][j]+map[i][j];
    for(int i=1;i<=n;i++) two[i]=two[i-1]+map[i][1]+map[i][2];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            for(int p=k;p>=1;p--)
            {
                dp[i][j][p]=max(dp[i][j-1][p],dp[i-1][j][p]);
                for(int i1=1;i1<=i;i1++)
                    dp[i][j][p]=max(dp[i][j][p],dp[i1-1][j][p-1]+res[i][1]-res[i1-1][1]);
                for(int i1=1;i1<=j;i1++)
                    dp[i][j][p]=max(dp[i][j][p],dp[i][i1-1][p-1]+res[j][2]-res[i1-1][2]);
                for(int i1=1;i1<=min(i,j);i1++)
                    dp[i][j][p]=max(dp[i][j][p],dp[i1-1][i1-1][p-1]+two[min(i,j)]-two[i1-1]);
            }
        }
    printf("%d
",dp[n][n][k]);
    return 0;
}
抄袭来的代码

emm。。。事实上博主想出了一种神奇的 nk 解法。。。

因为我们可以发现数据范围中的 m 是小于等于2的。。。那么假如m=1

这个dp方程应该是可以轻松推出来的。。。(博主推了半个小时

然后我们可以考虑如何拓展到m=2

因为其情况较少,那么对每一行读入的数我们维护如下几个情况就可以了。。。

0:这两个值宝宝都不选。。。QVQ

1:选取左边的,留下右边的。。。

2:选取右边的,留下左边的。。。

3:两个都选取,但是让他们分开成为两个集合。。。

(这里要特别说明一下。。。其实通过简单的意想就可以发现,实际上让他们单独成为两个集合和组成一个

 如果不加入别的操作。。。最后的结果都是一样的。。。但当我们需要进行 1,2 操作时。。。

 因为对于 f 数组我们要保证较坏的情况不被考虑。。。那么初始值除了 0 其他情况都是 -inf

 那么其前一个状态从哪里来呢?自然就是我的 3 操作了。。。QVQ)

4:两个都选,作为一个矩阵。。。

这样我们就可以动用神级垃圾操作:模拟

对一组数据进行手动模拟就好了。。。QVQ。。。dp柿子就推出来了。。。

其实大体思路明白了。。。柿子意会一下。。。手玩一下数据也就出来了。。。

呆码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define inf 999999
using namespace std;

int n,m,k,x,y,f[110][11][5];

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    if(m==1)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            for(int j=1;j<=k;j++)
            {
                f[i][j][1]=max(f[i-1][j][1],f[i-1][j-1][0])+x;
                f[i][j][0]=max(f[i-1][j][1],f[i-1][j][0]);
            }
        }
        printf("%d
",max(f[n][k][0],f[n][k][1]));
    }
    else
    {
        memset(f,-inf,sizeof(f));
        for(int i=0;i<=n;i++)
            for(int j=0;j<=k;j++)
                f[i][j][0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&x,&y);
            for(int j=1;j<=k;j++)
            {
                f[i][j][0]=max(f[i-1][j][0],max(max(f[i-1][j][1],f[i-1][j][2]),max(f[i-1][j][3],f[i-1][j][4])));
                f[i][j][1]=max(max(max(f[i-1][j-1][4],f[i-1][j-1][0]),f[i-1][j][3]),max(f[i-1][j][1],f[i-1][j-1][2]))+x;
                f[i][j][2]=max(max(max(f[i-1][j-1][4],f[i-1][j-1][0]),f[i-1][j][3]),max(f[i-1][j-1][1],f[i-1][j][2]))+y;
                f[i][j][3]=max(max(f[i-1][j-1][1],f[i-1][j-1][2]),f[i-1][j][3])+x+y;
                if(j>=2) f[i][j][3]=max(f[i][j][3],max(f[i-1][j-2][4],f[i-1][j-2][0])+x+y);
                f[i][j][4]=max(max(max(f[i-1][j-1][0],f[i-1][j-1][3]),max(f[i-1][j-1][1],f[i-1][j-1][2])),f[i-1][j][4])+x+y;
            }
        }
        printf("%d
",max(max(max(f[n][k][0],f[n][k][1]),max(f[n][k][2],f[n][k][3])),f[n][k][4]));
    }
}
蒟蒻的代码
原文地址:https://www.cnblogs.com/zzzyc/p/8946562.html