POJ-1050

来源:互联网 发布:win10网络图标没了 编辑:程序博客网 时间:2024/06/07 00:25

一道颇为经典的DP题。

首先,先看一个比该问题更简单更基础的问题:最大子序列和,或者叫最大子串和,连续子序列最大和等等。

问题很简答:给出一个一维数组A,求它的一个子数组,使得数组元素的和最大。

比如:给定数组A{5,-3,4,2},那么它的最大子序列为{5,-3,4,2},和为8,而{5,-6,4,2}的最大子序列是{4,2},和为6.仔细看这两个列子,我们会发现,找最大子序列的方法其实很简单:遍历原数组,假设当前扫描到第 i 个元素a ,假设以第 i-1 个元素为结尾的子序列和最大值b大于0,那么我们可以继续向后扫描,累加元素。反之,如果b小于0,那么如果把前面的串继续向后扩展,得到的和会比直接从a开始的子串小,所以应该把前面的串舍弃。同时,我们还应该记下每次算出的子序列和,如果比当前最大和大,则更新它。因为有可能出现所有元素都为负数的情况,所以最大和应该初始化为元素值的下限而不是0。

实例:

data:       1  -2  3  10  -4  7    2   -5

b:    0    1  -1  3  13  9   16  18  13

max:  -127  1   1     3  13  13   16  18  18

有了上面这个复杂度为O(n)的求一维数组最大子序列和的算法后,最大子矩阵和的问题就可以转化为这个问题从而得到解决了。首先是如何进行转化:一个矩阵的元素和,等于该矩阵中每一列的元素和再求和(相当于先把矩阵纵向压成一个数组,再把这个数组横向压成一个总和)。假设用c[i][j]表示方阵第 j 列前 i 行的元素和,那么c[i1][j] - c[i2 - 1][j]就可以表示第 j 列从第 i2 行到第 i1 行的元素之和。这样,对于每个行号 i1 和 i2,我们可以计算出每列在这两行之间的列元素和,这样就构成了一个一维数组,再对这个数组用上述最大子序列和算法,就可以得到由i2、i1确定上下边界的所有子阵的最大和了。由此,只需对所有的 i2<=i1 进行上述计算,记录找到的最大值即可。复杂度O(n^3)。

AC代码:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define N 1005int a[N][N];int c[N][N];int main(){    int n;    while(scanf("%d",&n)!=EOF)    {        int i,j,k;        for(i=0;i<n;i++)        {            for(j=0;j<n;j++)            {                scanf("%d",&a[i][j]);            }        }        memset(c,0,sizeof(c));        for(i=1;i<=n;i++)        {            for(j=0;j<n;j++)            {                c[i][j]=c[i-1][j]+a[i-1][j];            }        }        int t,sum=0;        int M=0;        for(i=1;i<=n;i++)        {            for(j=1;j<=i;j++)            {                sum=0;                for(k=0;k<n;k++)                {                    t=c[i][k]-c[j][k];                    if(sum>0)                    {                        sum+=t;                    }                    else                    {                        sum=t;                    }                    M=max(sum,M);                }            }        }        printf("%d\n",M);    }    return 0;}


0 0
原创粉丝点击