Skip to content

M02766: 最大子矩阵

binary, dp,kadane http://cs101.openjudge.cn/pctbook/M02766/

【姚博骞 25物院】思路:三种算法我都写了,其中分治比我想的难写很多,比一维要难,且复杂度只降到O(n^3log n) dp其实也包含了kadane的思想,无非是直接用kadane还是间接,两个方法的复杂度都是O(n^3)

cpp
#include<iostream>
#include<vector>
using namespace std;//kadane 算法
int max(int a,int b)
{
    return (a>b)?a:b;
}
int min(int a,int b)
{
    return(a<b)?a:b;
}
int juxing(int p,int q,int r,int s,vector<vector<int>>&qz)
{
    return qz[p][r]+qz[q][s]-qz[p][s]-qz[q][r];
}
int fenzhi(vector<vector<int>>&qz,int i1,int i2,int j1,int j2)
{
    int midi=0.5*(i1+i2);
    int midj=0.5*(j1+j2);
    int ans=-100000000;
    if((j2==j1)||(i2==i1)) return -10000000;
    if(i1!=i2)
    {
        int ans1=fenzhi(qz,i1,midi,j1,j2);
        int ans2=fenzhi(qz,midi+1,i2,j1,j2);
        ans=max(ans,max(ans1,ans2));
    }
    if(j1!=j2)
    {
        int ans1=fenzhi(qz,i1,i2,j1,midj);
        int ans2=fenzhi(qz,i1,i2,midj+1,j2);
        ans=max(ans,max(ans1,ans2));
    }
    int ans3,ans4;
    ans3=ans4=-100000000;
    for(int i=i1;i<=i2;i++)
    {
        for(int i_=i+1;i_<=i2;i_++)
        {
            int p,q;
            p=100000000;
            q=-100000000;
            for(int j=j1;j<=midj;j++)
            {
                p=min(p,juxing(i,i_,j1,j,qz));
            }
            for(int j=midj+1;j<=j2;j++)
            {
                q=max(q,juxing(i,i_,j1,j,qz));
            }
            ans3=max(q-p,ans3);
        }
    }
    for(int j=j1;j<=j2;j++)
    {
        for(int j_=j+1;j_<=j2;j_++)
        {
            int p,q;
            p=100000000;
            q=-100000000;
            for(int i=i1;i<=midi;i++)
            {
                p=min(p,juxing(i1,i,j,j_,qz));
            }
            for(int i=midi+1;i<=i2;i++)
            {
                q=max(q,juxing(i1,i,j,j_,qz));
            }
            ans4=max(q-p,ans4);
        }
    }
    ans=max(ans,max(ans3,ans4));
    return ans; 
}
int maxSubmatrix(vector<vector<int>>& a)
{
    int n = a.size();
    int m = a[0].size();
    int ans = -1e9;

    // 枚举上边界
    for(int top = 0; top < n; top++)
    {
        vector<int> sum(m, 0);  // 压缩后的数组

        // 枚举下边界
        for(int bottom = top; bottom < n; bottom++)
        {
            // 把这一行加进去(压缩列)
            for(int j = 0; j < m; j++)
                sum[j] += a[bottom][j];

            // ⭐ 在 sum 上跑一维 Kadane
            int cur = sum[0], best = sum[0];
            for(int j = 1; j < m; j++)
            {
                cur = max(sum[j], cur + sum[j]);
                best = max(best, cur);
            }

            ans = max(ans, best);
        }
    }
    return ans;
}
int kadane(vector<vector<int>>&a)
{
    int n=a.size();
    vector<vector<int>>lieqianzhui(n+1,vector<int>(n,0));
    vector<vector<int>>hangqianzhui(n,vector<int>(n+1,0));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            hangqianzhui[i][j+1]=hangqianzhui[i][j]+a[i][j];
        }   
    }
    for(int j=0;j<n;j++)
    {
        for(int i=0;i<n;i++)
        {
            lieqianzhui[i+1][j]=lieqianzhui[i][j]+a[i][j];
        }   
    }
    vector<vector<int>>dp(n,vector<int>(n,-10000000));
    vector<vector<vector<int>>>dpx(n,vector<vector<int>>(n));
    vector<vector<vector<int>>>dpy(n,vector<vector<int>>(n));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            int ans1,ans2;
            ans1=ans2=-100000000;
            for(int i1=0;i1<i;i1++)
            {
                dpx[i][j].push_back(((j>0)?max(0, dpx[i][j-1][i1]):0)+lieqianzhui[i+1][j]-lieqianzhui[i1+1][j]);
                ans1=max(ans1,dpx[i][j][i1]);
            }
            for(int j1=0;j1<j;j1++)
            {
                dpy[i][j].push_back(((i>0)?max(0,dpy[i-1][j][j1]):0)+hangqianzhui[i][j+1]-hangqianzhui[i][j1+1]);
                ans2=max(ans2,dpy[i][j][j1]);
            }
            dp[i][j]=max(max(ans1,ans2),a[i][j]);//kadane算法
        }
    }
    int ans=-1000000000;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            ans=max(ans,dp[i][j]);
        }
    }
    return ans;
}
int main()
{
    int n;
    cin>>n;
    vector<vector<int>>a(n,vector<int>(n));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            cin>>a[i][j];
        }
    }
    vector<vector<int>>qianzhui(n+1,vector<int>(n+1,0));
    vector<vector<int>>hangqianzhui(n,vector<int>(n+1,0));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            hangqianzhui[i][j+1]=hangqianzhui[i][j]+a[i][j];
            qianzhui[i+1][j+1]=hangqianzhui[i][j+1]+qianzhui[i][j+1];
        }   
    }
    cout<<maxSubmatrix(a);
    return 0;
}