POJ 1050 To the max 最大子矩阵

来源:互联网 发布:北京软件销售招聘 编辑:程序博客网 时间:2024/05/29 03:04

题目大意:给定一个N阶方阵(1<=N<=100),其元素的取值范围为[-127,127]。求其中的一个M*P维子矩阵(1<=M<=100,1<=P<=100),要求使该子矩阵中元素的和最大。

求最大子矩阵,大一的时候一个作业即是这个题目,忘了当时怎么写的了,重写一遍。首先求一维数组的最大子段,也是DP问题。

假设数组arr[SIZE],f[i] 是以“第i个位置为结束点的子段”的最大和。枚举所有位置,即枚举所有 i。注意到 f[i] 是包含 i 位置的最大和子段(假设不包含 i 位置,则在枚举到小于 i 位置(假设为 j 位置)时候已经算出包含 i 位置最大和子段),则有:

f[i] = max(f[i-1], 0)+arr[i]
.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }

意思是如果包含 i-1 点的最大和子段小于0,则对包含 i 点的最大和子段没有贡献,f[i] = arr[i]。反之,如果包含 i-1 点的最大和子段大于0,则对包含 i 点的最大和子段有正贡献,则需要加上:f[i] = f[i-1] + arr[i]

int sumSubArray(const int arr[], const int size)
{
    int endB=0, sum=MIN_INT;
    for (int i=0; i<size; i++)
    {
        if (endB>0)    endB += arr[i];
        else           endB = arr[i];
        
        if (sum<endB)    sum = endB;
    }
    return sum;
}
.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }

这就是用DP解决一位数组的最大和子段。参考

解决二维数组的最大子矩阵,转化为一维的即可。枚举从 i (i从0取到max_row)行到 j (j从i取到max_row)行,temp[SIZE]中的每个元素为第 i 行到第 j 行的每一列的和,对temp[]求最大子段即是对二维数组求最大子矩阵。我的代码如下:

   1: #include <iostream>
   2: using namespace std;
   3: const int MIN_INT = -(1<<15);
   4:  
   5: int sumSubArray(const int arr[], const int size)
   6: {
   7:     int endB=0, sum=MIN_INT;
   8:     for (int i=0; i<size; i++)
   9:     {
  10:         if (endB>0)    endB += arr[i];
  11:         else        endB = arr[i];
  12:  
  13:         if (sum<endB)    sum = endB;
  14:     }
  15:     return sum;
  16: }
  17:  
  18: int sumSubArray2(int** arr, const int row, const int col)
  19: {
  20:     int* temp = new int[col];
  21:     int sum = MIN_INT;
  22:     for (int i=0; i<row; i++)
  23:     {
  24:         for (int j=i; j<row; j++)
  25:         {
  26:             for (int t=0; t<col; t++)
  27:                 temp[t] = 0;
  28:  
  29:             for (int k=i; k<=j; k++)
  30:             {
  31:                 for (int pos=0; pos<col; pos++)
  32:                     temp[pos] += arr[k][pos];
  33:             }
  34:             int sumTemp = sumSubArray(temp, col);
  35:             if (sum<sumTemp)
  36:                 sum = sumTemp;
  37:         }
  38:     }
  39:     delete[] temp;
  40:     return sum;
  41: }
  42:  
  43: int main()
  44: {
  45:     int arrSize;
  46:     cin >> arrSize;
  47:     if (arrSize<=0)
  48:         return -1;
  49:     int** arr = new int* [arrSize];
  50:     arr[0] = new int[arrSize*arrSize];
  51:     for (int i=1; i<arrSize; i++)
  52:         arr[i] = arr[i-1] + arrSize;
  53:  
  54:     for (int i=0; i<arrSize; i++)
  55:     {
  56:         for (int j=0; j<arrSize; j++)
  57:             cin >> arr[i][j];
  58:     }
  59:  
  60:     int sum = sumSubArray2(arr, arrSize, arrSize);
  61:     cout << sum << endl;
  62:  
  63:     delete[] arr[0];
  64:     delete[] arr;
  65:     return 0;
  66: }

参考

原创粉丝点击