程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 矩形子數組的最大和

矩形子數組的最大和

編輯:C++入門知識

問題:給定m*n的矩陣,求具有最大和的矩形子數組。

先上暴力算法,求出所有矩形子數組的和,記錄其中最大值。思路就是從1*1的最小子矩陣開始(m*n個),到m*n的最大子矩陣(一個)結束,求出每個子矩陣的和,找出最大值。


[cpp]
/** @brief  在m*n的矩陣a中查找最大子矩陣的和
 ** @note   使用一維數組代替二維數組,
 **         元素a[i][j] = a[i*n+j].
 ** @return 最大子數組的和
 ** @author quickSort,
 ** @date   2013/08/10
 **     
 */ 
int maxSubMatrix_BF(int *a, int m, int n) 

    int mm=NM,sum=0; 
    for(int i=0;i<m;i++) 
    { 
        for(int j=0;j<n;j++) 
        {///for all a[i][j]  
            for(int ii=i;ii<m;ii++) 
            { 
                for(int jj=j;jj<n;jj++) 
                { 
                    sum = 0; 
                    for(int ti=i; ti<=ii;ti++) 
                        for(int tj=j; tj<=jj;tj++) 
                        { 
                            sum += a[ti*n+tj];///a[ii][jj] ///sum of a[i][j] -> a[ii][jj]  
                        } 
                    mm  = max(sum,mm); 
                } 
            } 
        } 
    } 
    cout<<__FUNCTION__<<": "<<mm<<endl; 
    return m; 

/** @brief  在m*n的矩陣a中查找最大子矩陣的和
 ** @note   使用一維數組代替二維數組,
 **         元素a[i][j] = a[i*n+j].
 ** @return 最大子數組的和
 ** @author quickSort,
 ** @date   2013/08/10
 **     
 */
int maxSubMatrix_BF(int *a, int m, int n)
{
    int mm=NM,sum=0;
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<n;j++)
        {///for all a[i][j]
            for(int ii=i;ii<m;ii++)
            {
                for(int jj=j;jj<n;jj++)
                {
                    sum = 0;
                    for(int ti=i; ti<=ii;ti++)
                        for(int tj=j; tj<=jj;tj++)
                        {
                            sum += a[ti*n+tj];///a[ii][jj] ///sum of a[i][j] -> a[ii][jj]
                        }
                    mm  = max(sum,mm);
                }
            }
        }
    }
    cout<<__FUNCTION__<<": "<<mm<<endl;
    return m;
}

為了使矩形的2維都可以是變量,這裡使用一維數組模擬二維矩陣,m*n的矩陣中元素a[i][j]對應於數組中的值就是a[i*n+j]。
其復雜度是多少呢……?一眼看去,6個for循環,OMG。。。像是O(m3n3).
顯然,復雜度太高了。。。。

===================================================================================================
結合一維最大子數組,可以這麼考慮:二維矩陣在某種程度上可以看做一位數組,而一維數組的每個元素又是一維數組。對於一維數組,最大子數組的和我們已經可以在O(n)內求出,而不需要O(n2)。

這裡再回憶一下這兩個算法:

 


平方算法:
[cpp]
///算法1.  
///在數組a[n]中找出子數組的最大和  
void    maxSum_1(int a[], int n) 

    int sum=NM,m=NM;//NM是一個很小的負數,例如-99999999.下同  
    for(int i=0; i<n; i++) 
    { 
        sum=0; 
        for(int j=i; j<n; j++) 
        { 
            sum += a[j]; 
            m = max(m,sum); 
        } 
    } 
    cout<<__FUNCTION__<<" : "<<m<<endl; 

///算法1.
///在數組a[n]中找出子數組的最大和
void    maxSum_1(int a[], int n)
{
    int sum=NM,m=NM;//NM是一個很小的負數,例如-99999999.下同
    for(int i=0; i<n; i++)
    {
        sum=0;
        for(int j=i; j<n; j++)
        {
            sum += a[j];
            m = max(m,sum);
        }
    }
    cout<<__FUNCTION__<<" : "<<m<<endl;
}
掃描算法:

[cpp]
///算法2,掃描算法  
///在數組a[n]中找出子數組的最大和  
void    maxSum_3(int a[], int n) 

    int maxSoFar=NM, maxEndingHere=NM; 
    for(int i=0; i<n; i++) 
    { 
        maxEndingHere = max(maxEndingHere+a[i], a[i]); 
        maxSoFar = max(maxSoFar,maxEndingHere); 
    } 
    cout<<__FUNCTION__<<" : "<< maxSoFar <<endl; 

///算法2,掃描算法
///在數組a[n]中找出子數組的最大和
void    maxSum_3(int a[], int n)
{
    int maxSoFar=NM, maxEndingHere=NM;
    for(int i=0; i<n; i++)
    {
        maxEndingHere = max(maxEndingHere+a[i], a[i]);
        maxSoFar = max(maxSoFar,maxEndingHere);
    }
    cout<<__FUNCTION__<<" : "<< maxSoFar <<endl;
}

對於行向量(m個),使用普通的平方算法,即算法1,
對於列向量(n個),使用掃描算法,即算法2。
具體代碼如下:
[cpp]
/** @brief  在m*n的矩陣a中查找最大子矩陣的和
 ** @note   使用一維數組代替二維數組,
 **         元素a[i][j] = a[i*n+j].
 ** @return 最大子數組的和
 ** @author quickSort,
 ** @date   2013/08/10
 **        
 */ 
int maxSubMatrix(int *a, int m, int n) 

    int i,j,k; 
    int maxSoFar=NM,maxEndingHere; 
    int *sum = (int*)malloc(sizeof(int)*n); 
    for(i=0;i<m;i++) 
    { 
        memset(sum,0,sizeof(int)*n);///sum=0  
        for(j=i;j<m;j++)///在m維度上使用平平方算法  
        { 
            maxEndingHere = 0; 
            for(k=0;k<n;k++)///在n維度上使用掃描算法  
            { 
                sum[k] += a[j*n+k];///a[j*n+k]=a[j][k]  
                maxEndingHere=max(maxEndingHere+sum[k],sum[k]); 
                maxSoFar = max(maxSoFar,maxEndingHere); 
            } 
        } 
    } 
    free(sum); 
    cout<<__FUNCTION__<<" : "<<maxSoFar<<endl; 
    return maxSoFar; 

/** @brief  在m*n的矩陣a中查找最大子矩陣的和
 ** @note   使用一維數組代替二維數組,
 **         元素a[i][j] = a[i*n+j].
 ** @return 最大子數組的和
 ** @author quickSort,
 ** @date   2013/08/10
 **     
 */
int maxSubMatrix(int *a, int m, int n)
{
    int i,j,k;
    int maxSoFar=NM,maxEndingHere;
    int *sum = (int*)malloc(sizeof(int)*n);
    for(i=0;i<m;i++)
    {
        memset(sum,0,sizeof(int)*n);///sum=0
        for(j=i;j<m;j++)///在m維度上使用平平方算法
        {
            maxEndingHere = 0;
            for(k=0;k<n;k++)///在n維度上使用掃描算法
            {
                sum[k] += a[j*n+k];///a[j*n+k]=a[j][k]
                maxEndingHere=max(maxEndingHere+sum[k],sum[k]);
                maxSoFar = max(maxSoFar,maxEndingHere);
            }
        }
    }
    free(sum);
    cout<<__FUNCTION__<<" : "<<maxSoFar<<endl;
    return maxSoFar;
}


其復雜度為O(m2n)。

完整測試代碼:

[cpp]
#include    <iostream>  
#include    <algorithm>  
#include    <cstring>  
///  
/** @brief  矩形子數組的最大和 完整測試代碼
 ** @author quickSort,
 ** @date   2013/08/10
 **        
 **         
 */ 
 
using namespace std; 
 
int d[] = {-3,-2,-67,-7,-9,-8}; 
int c[] = {1,-2,3,10,-4,7,2,-5}; 
int e[] =   /// 2*8 || 4*4  
            { 1,-2, 3,10, 
             -4, 7, 2,-5, 
              1,-8,-5,-9, 
              7,10,-6,-20 
            }; 
const int   NM = -99999; 
 
void    maxSum_1(int a[], int n) 

    int sum=NM,m=NM; 
    for(int i=0; i<n; i++) 
    { 
        sum=0; 
        for(int j=i; j<n; j++) 
        { 
            sum += a[j]; 
            m = max(m,sum); 
        } 
    } 
    cout<<__FUNCTION__<<" : "<<m<<endl; 

 
void    maxSum_3(int a[], int n) 

    int maxSoFar=NM, maxEndingHere=NM; 
    for(int i=0; i<n; i++) 
    { 
        maxEndingHere = max(maxEndingHere+a[i], a[i]); 
        maxSoFar = max(maxSoFar,maxEndingHere); 
    } 
    cout<<__FUNCTION__<<" : "<< maxSoFar <<endl; 

 
template  <typename T> 
inline  T   abs(T n) 

    return  n<0?(-n):n; 

 
///-----------------------------------------  
/** @brief  在m*n的矩陣a中查找最大子矩陣的和
 ** @note   使用一維數組代替二維數組,
 **         元素a[i][j] = a[i*n+j].
 ** @return 最大子數組的和
 ** @author quickSort,
 ** @date   2013/08/10
 **
 */ 
int maxSubMatrix(int *a, int m, int n) 

    int i,j,k; 
    int maxSoFar=NM,maxEndingHere; 
    int *sum = (int*)malloc(sizeof(int)*n); 
    for(i=0;i<m;i++) 
    { 
        memset(sum,0,sizeof(int)*n);///sum=0  
        for(j=i;j<m;j++) 
        { 
            maxEndingHere = 0; 
            for(k=0;k<n;k++) 
            { 
                sum[k] += a[j*n+k];///a[j*n+k]=a[j][k]  
                maxEndingHere=max(maxEndingHere+sum[k],sum[k]); 
                maxSoFar = max(maxSoFar,maxEndingHere); 
            } 
        } 
    } 
    free(sum); 
    cout<<__FUNCTION__<<" : "<<maxSoFar<<endl; 
    return maxSoFar; 

/** @brief  在m*n的矩陣a中查找最大子矩陣的和
 ** @note   使用一維數組代替二維數組,
 **         元素a[i][j] = a[i*n+j].
 ** @return 最大子數組的和
 ** @author quickSort,
 ** @date   2013/08/10
 **
 */ 
int maxSubMatrix_BF(int *a, int m, int n) 

    int mm=NM,sum=0; 
    for(int i=0;i<m;i++) 
    { 
        for(int j=0;j<n;j++) 
        {///for all a[i][j]  
            for(int ii=i;ii<m;ii++) 
            { 
                for(int jj=j;jj<n;jj++) 
                { 
                    sum = 0; 
                    for(int ti=i; ti<=ii;ti++) 
                        for(int tj=j; tj<=jj;tj++) 
                        { 
                            sum += a[ti*n+tj];///a[ii][jj] ///sum of a[i][j] -> a[ii][jj]  
                        } 
                    mm  = max(sum,mm); 
                } 
            } 
        } 
    } 
    cout<<__FUNCTION__<<": "<<mm<<endl; 
    return m; 

 
int main() 

    int n   = sizeof(c)/sizeof(int); 
    int a[100]; 
    reset(a,n); 
    maxSum_1(a,n); 
 
    maxSum_3(a,n); 
 
    maxSubMatrix(e,4,4); 
    maxSubMatrix_BF(e,4,4); 
    return 0; 

#include    <iostream>
#include    <algorithm>
#include    <cstring>
///
/** @brief  矩形子數組的最大和 完整測試代碼
 ** @author quickSort,
 ** @date   2013/08/10
 **       
 **        
 */

using namespace std;

int d[] = {-3,-2,-67,-7,-9,-8};
int c[] = {1,-2,3,10,-4,7,2,-5};
int e[] =   /// 2*8 || 4*4
            { 1,-2, 3,10,
             -4, 7, 2,-5,
              1,-8,-5,-9,
              7,10,-6,-20
            };
const int   NM = -99999;

void    maxSum_1(int a[], int n)
{
    int sum=NM,m=NM;
    for(int i=0; i<n; i++)
    {
        sum=0;
        for(int j=i; j<n; j++)
        {
            sum += a[j];
            m = max(m,sum);
        }
    }
    cout<<__FUNCTION__<<" : "<<m<<endl;
}

void    maxSum_3(int a[], int n)
{
    int maxSoFar=NM, maxEndingHere=NM;
    for(int i=0; i<n; i++)
    {
        maxEndingHere = max(maxEndingHere+a[i], a[i]);
        maxSoFar = max(maxSoFar,maxEndingHere);
    }
    cout<<__FUNCTION__<<" : "<< maxSoFar <<endl;
}

template  <typename T>
inline  T   abs(T n)
{
    return  n<0?(-n):n;
}

///-----------------------------------------
/** @brief  在m*n的矩陣a中查找最大子矩陣的和
 ** @note   使用一維數組代替二維數組,
 **         元素a[i][j] = a[i*n+j].
 ** @return 最大子數組的和
 ** @author quickSort,
 ** @date   2013/08/10
 **
 */
int maxSubMatrix(int *a, int m, int n)
{
    int i,j,k;
    int maxSoFar=NM,maxEndingHere;
    int *sum = (int*)malloc(sizeof(int)*n);
    for(i=0;i<m;i++)
    {
        memset(sum,0,sizeof(int)*n);///sum=0
        for(j=i;j<m;j++)
        {
            maxEndingHere = 0;
            for(k=0;k<n;k++)
            {
                sum[k] += a[j*n+k];///a[j*n+k]=a[j][k]
                maxEndingHere=max(maxEndingHere+sum[k],sum[k]);
                maxSoFar = max(maxSoFar,maxEndingHere);
            }
        }
    }
    free(sum);
    cout<<__FUNCTION__<<" : "<<maxSoFar<<endl;
    return maxSoFar;
}
/** @brief  在m*n的矩陣a中查找最大子矩陣的和
 ** @note   使用一維數組代替二維數組,
 **         元素a[i][j] = a[i*n+j].
 ** @return 最大子數組的和
 ** @author quickSort,
 ** @date   2013/08/10
 **
 */
int maxSubMatrix_BF(int *a, int m, int n)
{
    int mm=NM,sum=0;
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<n;j++)
        {///for all a[i][j]
            for(int ii=i;ii<m;ii++)
            {
                for(int jj=j;jj<n;jj++)
                {
                    sum = 0;
                    for(int ti=i; ti<=ii;ti++)
                        for(int tj=j; tj<=jj;tj++)
                        {
                            sum += a[ti*n+tj];///a[ii][jj] ///sum of a[i][j] -> a[ii][jj]
                        }
                    mm  = max(sum,mm);
                }
            }
        }
    }
    cout<<__FUNCTION__<<": "<<mm<<endl;
    return m;
}

int main()
{
    int n   = sizeof(c)/sizeof(int);
    int a[100];
    reset(a,n);
    maxSum_1(a,n);

    maxSum_3(a,n);

    maxSubMatrix(e,4,4);
    maxSubMatrix_BF(e,4,4);
    return 0;
}

 

結果:
[plain]

maxSum_1 : 18 
maxSum_3 : 18 
maxSubMatrix : 17 
maxSubMatrix_BF: 17 
 
 
Process returned 0 (0x0)   execution time : 0.296 s 
Press any key to continue. 

maxSum_1 : 18
maxSum_3 : 18
maxSubMatrix : 17
maxSubMatrix_BF: 17


Process returned 0 (0x0)   execution time : 0.296 s
Press any key to continue.


 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved