• 最大子矩阵和


     问:给定一个N*M的矩阵,其子矩阵有N*M*N*M个子矩阵,将子矩阵中的每个元素求和,求和最大的子矩阵。

    我们可以枚举每个子矩阵,时间复杂度为0(N*M*N*M),代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int MAXN=105;
    int mat[MAXN][MAXN];
    int sum[MAXN][MAXN];
    int n;
    int main()
    {
        while(scanf("%d",&n)!=EOF)
        {
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    scanf("%d",&mat[i][j]);
            
            sum[1][1]=mat[1][1];
            for(int i=2;i<=n;i++)
                sum[1][i]=sum[1][i-1]+mat[1][i];
            for(int i=2;i<=n;i++)
                sum[i][1]=sum[i-1][1]+mat[i][1];
            
            for(int i=2;i<=n;i++)
                for(int j=2;j<=n;j++)
                {
                    sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+mat[i][j];//sum[i][j]表示左上角为mat[1][1],右下角为mat[i][j]所表示的矩阵之和
                }
            
            int res=-10000000;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    for(int x=i;x<=n;x++)
                        for(int y=j;y<=n;y++)
                        {
                            int total=sum[x][y]-sum[x][j-1]-sum[i-1][y]+sum[i-1][j-1];
                            if(total>res)
                                res=total;
                        }
                        
            printf("%d
    ",res);
        }
        return 0;
    }

    不过我们可以优化到o(N2*M)我们之前遇到过一个一维数组中最大子段和的问题。其状态转移方程为 if(b[i-1]>0) b[i]=b[i-1]+a[i] else b[i]=a[i],

    其时间复杂度为0(N),代码如下:

    int MaxSubSegSum(int num[])
    {
        int b[MAXN],maxn;
        maxn=b[0]=num[0];
        for(int i=1;i<m;i++)
        {
            if(b[i-1]>0)    b[i]=b[i-1]+num[i];
            else    b[i]=num[i];
            maxn=max(maxn,b[i]);
        }
        return maxn;
    }

     我们可以这样想:我们任意取第i行到第j行列全包含的子矩阵。我们将每行求和,转化为求最大子段和问题。我们就可以在O(M)的时间内枚举M*(M+1)/2个子矩阵,而这样的列全包含矩阵有

    N*(N+1)/2 个。这样我们就可以在O(N*N*M)的时间内求得,这样大大降低了时间复杂度。

    完整代码如下:

    #include"cstdio"
    #include"cstring"
    #include"algorithm"
    using namespace std;
    const int MAXN=1005;
    int n,m;
    int matrix[MAXN][MAXN];
    int l,r,up,down;
    int ll,rr;
    int lll,rrr;
    int MaxSubSegSum(int num[])
    {
        int b[MAXN],maxn;
        maxn=b[0]=num[0];
        l=r=0;
        for(int i=1;i<m;i++)
        {
            if(b[i-1]>0)
            {
                b[i]=b[i-1]+num[i];
                r=i;
            }
            else
            {
                b[i]=num[i];
                r=i;
                l=i;
            }
            if(maxn<b[i])
            {
                maxn=b[i];
                ll=l;
                rr=r;
            }
        }
        return maxn;
    }
    int total[MAXN][MAXN];
    int MaxSubMat()
    {
        for(int j=0;j<m;j++)    total[0][j]=matrix[0][j];
        for(int i=1;i<n;i++)
            for(int j=0;j<m;j++)
            {
                total[i][j]=matrix[i][j];
                total[i][j]+=total[i-1][j];
            }
        int maxn=-0x3fffffff;
        int temp[MAXN];
        for(int i=0;i<n;i++)
        {
            for(int j=i;j<n;j++)
            {
                for(int z=0;z<m;z++)
                {
                    if(i==0)    temp[z]=total[j][z];
                    else    temp[z]=total[j][z]-total[i-1][z];
                }
                if(MaxSubSegSum(temp)>maxn)
                {
                    maxn=MaxSubSegSum(temp);
                    up=i;
                    down=j;    
                    lll=ll;
                    rrr=rr;
                }
            }
        }
        return maxn;
    }
    int main()
    {
        scanf("%d%d",&m,&n);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)    scanf("%d",&matrix[i][j]);
        int ans=MaxSubMat();
        printf(" 最大子矩阵为:
    ");
        for(int i=up;i<=down;i++)
        {
            for(int j=lll;j<=rrr;j++)    printf("%d ",matrix[i][j]);
            printf("
    ");
        }
        printf("其和为:%d
    ",ans);
        return 0;
    }
    /*
    3 3
    -1 3 -1
    2 -1 3
    -3 1 2
    
    3 -1
    -1 3
    1 2
    7
    */
  • 相关阅读:
    Ajax函数
    javascript 重定向和打开新窗口(ZZ)
    asp.net 学习
    dojo杂谈
    Deciding between COALESCE and ISNULL in SQL Server
    从 Twitter 运维技术经验可以学到什么
    重新安装ASP.NET命令
    SQL Server 2008中新增的变更数据捕获(CDC)和更改跟踪
    SQL Server 2005/2008/2012中应用分布式分区视图
    数据库运维原则
  • 原文地址:https://www.cnblogs.com/program-ccc/p/5187609.html
Copyright © 2020-2023  润新知