Maximum Sum

Maximum Sum

 

Time Limit:   1000MS       Memory Limit:   65535KB
Submissions:   26       Accepted:   18

 

Description

给你一个NxN的阵列,请你找出有最大和的子区域(sub-rectangle)。一个区域的和指的是该区域中所有元素值的和。一个区域是指相连的任意大小的子阵列。例如,以下的二维阵列:

0 -2 -7 0

9 2 -6 2

-4 1 -4 1

-1 8 0 -2

其最大和的子区域位于左下角,并且其和为15。如下所示:

9 2

-4 1

-1 8

 

Input

只有一组测试数据,第一列有一个正整数N(N <= 100),代表此二维阵列大小为NxN。 从第二列起有N2 个整数,代表此阵列的內容。每个整数都介于-127到127之间,且以列为主(row-major)的顺序排列。Sample Input即为上面所示的阵列。

 

Output

输出最大和的子区域的和。

 

Sample Input

4
0 -2 -7  0 
9 2 -6 2 -4 1 -4 1
-1 8 0 -2

 

Sample Output

15

 

分析:

【解法一】

题意很清晰,首先用人人都能想到的方法,确定个起点,在确定个终点,将它们形成矩形内的数的和算出来就行了,六个for语句,时间复杂度可想而知;而且现在n在100内,如果n再大一点,显然就通不过了

代码如下:

 

# include<stdio.h>
#define inf 99999
int main()
{
    int n;
    int i,j,e,f,l,m;
    int sum,Maxnum=-inf;
    int Map[102][102];
    scanf("%d",&n);
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            scanf("%d",&Map[i][j]);
    for(i=0;i<n;i++)//确定起点
    {
        for(j=0;j<n;j++)
        {
            for(e=i;e<n;e++)//确定终点
            {
                for(f=j;f<n;f++)
                {
                    sum=0;
                    for(l=i;l<=e;l++)//将和算出来
                        for(m=j;m<=f;m++)
                            sum+=Map[l][m];
                    if(sum>Maxnum)
                        Maxnum=sum;
                }
            }
        }
    }
    printf("%d\n",Maxnum);
    return 0;
}

由于对于每行而言,每次都是在前面的基础上加了一列,因此可以优化一下
代码如下:

# include<stdio.h>
#define inf 99999
int main()
{
    int n;
    int i,j,e,f,l;
    int sum,Maxnum=-inf;
    int Map[102][102];
    scanf("%d",&n);
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            scanf("%d",&Map[i][j]);
    for(i=0;i<n;i++)//确定起点
    {
        for(j=0;j<n;j++)
        {
            for(e=i;e<n;e++)//确定终点
            {        
                sum=0;//换一行就清零,重新计算
                for(f=j;f<n;f++)
                {
                    for(l=i;l<=e;l++)//在前面的基础上加一列
                            sum+=Map[l][f];
                    if(sum>Maxnum)
                        Maxnum=sum;
                }
            }
        }
    }
    printf("%d\n",Maxnum);
    return 0;
}

【解法二】

即使优化了,n大了,肯定也不行;那再思考另一种算法吧
考虑起始点和终点,不得不用上4个for语句,那如果考虑到起始行和末尾行,两个for语句就行了

代码如下:

# include<stdio.h>
# include<string.h>
#define inf 99999
int n;
int solve(int dp[])
{
    int i;
    int add=-inf,sum=-inf;
    for(i=0;i<n;i++)
    {
        if(add>0)
            add+=dp[i];
        else add=dp[i];
        if(add>sum)
            sum=add;
    }
    return sum;
}
int main()
{
    int i,j,e;
    int sum,Maxnum=-inf;
    int Map[102][102],dp[102];
    scanf("%d",&n);
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            scanf("%d",&Map[i][j]);
    for(i=0;i<n;i++)//调整起始行
    {
        memset(dp,0,sizeof(dp));
        for(j=i;j<n;j++)//移动末尾行
        {
            for(e=0;e<n;e++)//移动一次加一次
            {
                dp[e]+=Map[j][e];
            }
            sum=solve(dp);//获得第i行到第j行(含有第i行和第j行)上的最大子矩阵
            if(sum>Maxnum)//并同时判断一次
                Maxnum=sum;
        }
    }
    printf("%d\n",Maxnum);
    return 0;
}

 

posted on 2012-11-13 08:11  即为将军  阅读(301)  评论(0)    收藏  举报

导航