zoukankan      html  css  js  c++  java
  • 数组的子数组之和的最大值(二维)

    #include<iostream>
    #define MAX 100
    using namespace std;
    
    int A[MAX][MAX];
    int PS[MAX][MAX];
    //method1
    /*
    最直接的方法,当然是枚举每一个矩形区域,然后再求这个矩形区域中元素的和。时间复杂度为O(N^2 * M^2 * Sum的时间复杂度)
    */
    int max(int x,int y)
    {
     return (x>y)?x:y;
    }
    int Sum(int i_min,int i_max,int j_min,int j_max)
    {
     int s=0;
        for(int i=i_min;i<=i_max;i++)
      for(int j=j_min;j<=j_max;j++)
      {
           s+=A[i][j];
      }
      return s;
    }
    int MaxSum(int N,int M)
    {
     int maximum=A[1][1];
         for(int i_min=1;i_min<=N;i_min++)
       for(int i_max=i_min;i_max<=N;i_max++)
        for(int j_min=1;j_min<=M;j_min++)
         for(int j_max=j_min;j_max<=M;j_max++)
         {
              maximum=max(maximum,Sum(i_min,i_max,j_min,j_max));
         }
         return maximum;
    }
    
    //method2
    /*
    在二维情况下,定义“部分和”P[i][j]等于以(1,1),(i,1),(1,j),(i,j)为顶点的矩形区域的元素之和。
    通过画图可以看出,以(i_min,j_min),(i_min,j_max),(i_max,j_min),(i_max,j_max)为顶点的矩形区域的元素之和
    等于PS[i_max][j_max]-PS[i_min-1][j_max]-PS[i_max][j_min-1]+PS[i_min-1][j_min-1],也就是在已知“部分和”的基础
    上可以用O(1)时间算出任意矩阵区域的元素之和。
    
    不难看出,在更小的“部分和”的基础上,也能以O(1)时间得到新的“部分和”。
    PS[i][j]=PS[i-1][j]+PS[i][j-1]-PS[i-1][j-1]+B[i][j] O(N*M)的时间就足够预处理并得到所有部分和。
    综上所述,我们得到了一个O(N^2 * M^2)的解法。
    */
    
    void CalcPS(int N,int M)
    {
         for(int i=0;i<=N;i++)PS[i][0]=0;
      for(int j=0;j<=M;j++)PS[0][j]=0;
      for(int i=1;i<=N;i++)
       for(int j=1;j<=M;j++)
       {
           PS[i][j]=PS[i-1][j]+PS[i][j-1]-PS[i-1][j-1]+A[i][j];
       }
    }
    int MaxSum2(int N,int M)
    {
     int maximum=A[1][1];
         for(int i_min=1;i_min<=N;i_min++)
       for(int i_max=i_min;i_max<=N;i_max++)
        for(int j_min=1;j_min<=M;j_min++)
         for(int j_max=j_min;j_max<=M;j_max++)
         {
             maximum=max(maximum,PS[i_max][j_max]-PS[i_min-1][j_max]-PS[i_max][j_min-1]+PS[i_min-1][j_min-1]);
         }
         return maximum;
    }
    
    //method3
    /*
    我们发现一维的解答可以线性完成。如果我们能将二维问题转换为一维问题,或许可以改进一下。
    可以把每一列中第a行和第c行之间的元素看出一个整体。即求数组(BC(1),BC(2),...,BC(M))中的
    最大的一段,其中BC[i]=B[a][i]+...+B[c][i]
    我们枚举矩形上下边界,然后再用一维情况下的方法确定左右边界,就可以得到二维问题的解。
    时间复杂度为O(N^2 * M)
    */
    
    int MaxSum3(int N,int M)
    {
     int *a=new int[M];
     int* b=new int[M];
     int maximum=A[1][1];
     for(int i=1;i<=N;i++)
     {
             memset(a,0,sizeof(int)*M);
       for(int j=i;j<=N;j++)
       {
           for(int k=1;k<=M;k++)
        {
             a[k-1]+=A[j][k];
        }
                 memset(b,0,sizeof(int)*M);
        b[0]=a[0];
        for(int k=1;k<=M;k++)
        {
             if(b[k-1]<0)b[k]=a[k];
          else b[k]=b[k-1]+a[k];
          if(b[k]>maximum)maximum=b[k];
        }
       }
     }
     return maximum;
    }
    
    int main()
    {
     int N,M;
     
     while(cin>>N>>M)
     {
      if(N==0 && M==0)break;
      memset(A,0,sizeof(int)*N*M);
      memset(PS,0,sizeof(int)*N*M);
            for(int i=1;i<=N;i++)
             for(int j=1;j<=M;j++)
       {
           cin>>A[i][j];
       }
       
      int max=MaxSum(N,M);
      cout<<"子数组之和的最大值为: "<<max<<endl;
            
            CalcPS(N,M);
      max=MaxSum2(N,M);
            cout<<"子数组之和的最大值为: "<<max<<endl;
    
      max=MaxSum3(N,M);
            cout<<"子数组之和的最大值为: "<<max<<endl;
     }
        system("pause");
     return 0;
    }
    

      

  • 相关阅读:
    websocket在线测试工具
    短信线上发送错误,线下成功
    nginx添加stream模块1.20
    sort 的使用
    实验、进程的同步与互斥——生产者消费者
    实验、可变分区存储管理系统模拟 —— 最先适应分配算法
    test
    c++的大数阶乘算法
    C#解析JSON字符串总结
    C++ 查看单个类对象模型利用Vs开发者命令提示工具
  • 原文地址:https://www.cnblogs.com/yanglf/p/2758139.html
Copyright © 2011-2022 走看看