动态规划(DP)——HDU1081、PKU1050 To The Max 最大子矩阵问题

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1081


题目大意:给定1个n*n矩阵,求最大子矩阵(矩阵元素之和最大)。


解题思路:

这个题目和那个最大连续子序列是比较像的,只是维数不同而已。

如果能把二维的问题转化成一维的,那么这个问题就迎刃而解了。

二维转一维的方法就是枚举任意两行,然后求出这两行之间任意一列之和,

这样就得到了一个一维数组,接下来的做法就是求最大连续子序列。

这个题目需要预处理,sum[i][j],表示前i行第j列之和,b[k]=sum[j][k]-sum[i][k];

最大连续子序列的状态转移方程:c[k]=max(c[k-1]+b[k],b[k]);

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
int a[101][101];
int sum[101][101];  //表示前i行第j列之和
int b[101];         //表示最后需要进行运算的数据
int c[101];
int main()
{
    int n,i,j,mmax,k;
    while(scanf("%d",&n)==1)
    {
        memset(a,0,sizeof(a));
        memset(sum,0,sizeof(sum));
        memset(b,0,sizeof(b));
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                scanf("%d",&a[i][j]);
        //预处理前i行第j列的和
        //第1行之和
        for(i=1;i<=n;i++)
        {
            sum[1][i]=a[1][i];
        }
        for(i=2;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                sum[i][j]=sum[i-1][j]+a[i][j];
            }
        }
        //枚举每两行求取最大子矩阵之和
        mmax=-99999999;
        for(i=0;i<=n-1;i++)
        {
            for(j=i+1;j<=n;j++)
            {
                memset(b,0,sizeof(b));
                for(k=1;k<=n;k++)
                {
                    b[k]=sum[j][k]-sum[i][k];
                }
                //求最大子段和
                memset(c,0,sizeof(c));
                c[1]=b[1];
                if(c[1]>mmax)   mmax=c[1];
                for(k=2;k<=n;k++)
                {
                    if(c[k-1]>0)    c[k]=c[k-1]+b[k];
                    else    c[k]=b[k];
                    if(c[k]>mmax)   mmax=c[k];
                }
            }
        }
        printf("%d\n",mmax);
    }
    return 0;
}


你可能感兴趣的:(动态规划(DP)——HDU1081、PKU1050 To The Max 最大子矩阵问题)