zoukankan      html  css  js  c++  java
  • [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]));
        }
    }
    蒟蒻的代码
  • 相关阅读:
    qt捕鱼达人
    linux通过源码安装gdb
    打造简易http服务器
    linux缓存同步
    NOI之后的碎碎念
    Validate至少有一个不能为空
    IOI 2020 集训队作业
    P6033 [NOIP2004 提高组] 合并果子 加强版 题解
    P3017 [USACO11MAR]Brownie Slicing G 题解
    LOJ #145. DFS 序 2 题解
  • 原文地址:https://www.cnblogs.com/zzzyc/p/8946562.html
Copyright © 2011-2022 走看看