• [SCOI2005] 最大子矩阵


    题目链接:https://ac.nowcoder.com/acm/problem/20242

    思路:
    因为m最大只有2,所以可以先算m==1的时候,就相当于求最大m子串和,状态转移方程为 :
    dp[i][k][0]=max(dp[i-1][k][0],dp[i-1][1][k]);
    dp[i][k][1]=max(dp[i-1][k][1],max(dp[i-1][k-1][1],dp[i-1][k-1][0]))+num[i];

    然后m==2的时候,用dp[i][j][k]来表示,第一列为1-i,第二列为1-j,k为选的k个矩形。 sum[n][1]表示第一列的前缀和,sum[n][2]表示第二列的前缀和。
    计算的时候,我们可以当做是分别计算第一列和第二列的最大m子串和,然后再把他们两列进行整合,因此可以分为四种情况:
    计算第一列的时候:
    dp[i][j][k]=max(dp[i][j][k],dp[t][j][k-1]+sum[i][1]-sum[t][1]);
    计算第二列的时候:
    dp[i][j][k]=max(dp[i][j][k],dp[i][t][k-1]+sum[j][2]-sum[t][2]);
    当i==j的时候,会有他们两列的子串重合为一个矩形的可能:
    dp[i][j][k]=max(dp[i][j][k],dp[t][t][k-1]+sum[i][1]-sum[t][1]+sum[j][2]-sum[t][2]);
    什么都不选的情况:
    dp[i][j][k]=max(dp[i-1][j][k],dp[i][j-1][k]);

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #include <stack>
    #include <queue>
    #include <cmath>
    #define ll long long
    #define pi 3.1415927
    #define inf 0x3f3f3f3f
    #define mod 1000000007
    using namespace std;
    int sum[105][5],dp[105][105][12],num[105][5];
    int main ()
    {
        
        int T,n,m,i,t,j,k,p;
        cin>>n>>m>>k;
        for(i=1;i<=n;++i)
            for(j=1;j<=m;++j){
                cin>>num[i][j];
                sum[i][j]=sum[i-1][j]+num[i][j]; //计算前缀和
            }
        
        if(m==1)
        {
            for(i=1;i<=n;++i)
                for(int kk=1;kk<=k;++kk){//m==1的时候,相当于求最大m子串和
                    dp[i][0][kk]=max(dp[i-1][0][kk],dp[i-1][1][kk]);
                    dp[i][1][kk]=max(dp[i-1][1][kk],max(dp[i-1][1][kk-1],dp[i-1][0][kk-1]))+num[i][1];
                }
            p=max(dp[n][1][k],dp[n][0][k]);
            cout<<p<<endl;
        }
        else 
        {
            for(i=1;i<=n;++i)
                for(j=1;j<=n;++j)
                    for(int kk=1;kk<=k;++kk)
                    {
                        dp[i][j][kk]=max(dp[i-1][j][kk],dp[i][j-1][kk]); //什么都不选的情况
                        for(t=0;t<i;++t)
                            dp[i][j][kk]=max(dp[i][j][kk],dp[t][j][kk-1]+sum[i][1]-sum[t][1]); //在第一列选区间
                        for(t=0;t<j;++t)
                            dp[i][j][kk]=max(dp[i][j][kk],dp[i][t][kk-1]+sum[j][2]-sum[t][2]); //在第二列选区间
                        if(i==j)
                            for(t=0;t<j;++t) //当i==j的时候,有可能出现区间相同的情况
                                dp[i][j][kk]=max(dp[i][j][kk],dp[t][t][kk-1]+sum[i][1]-sum[t][1]+sum[j][2]-sum[t][2]);
                    }
            cout<<dp[n][n][k]<<endl;
        }
        return 0;
    }
  • 相关阅读:
    Java线上应用故障排查之一:高CPU占用【转】
    JAVA 之 Tomcat知识框架【转】
    FileZilla 配置备份与还原【转】
    linux删除第几天日志【原创】
    sar命令使用【转】
    Mysql Group Replication 简介及单主模式组复制配置【转】
    grep 中的正则表达式【转】
    java程序out of memory【转】
    Java笔记18:JUnit单元测试
    Java笔记17:导出可执行jar包
  • 原文地址:https://www.cnblogs.com/blowhail/p/13073295.html
Copyright © 2020-2023  润新知