码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 1081 To The Max 暴力模拟O(n^4) dp优化O(n^3)

时间:2015-08-12 21:50:42      阅读:137      评论:0      收藏:0      [点我收藏+]

标签:动态规划

原题: http://acm.hdu.edu.cn/showproblem.php?pid=1081

题目大意:
求给定边长的正方形选一个矩形,使它包含的所有元素的值最大。

大家都知道(a+b)^2的展开式,这里的优化就是用了这个原理来做的优化,我们的dp值是我们前i行j列的矩形区域的值。
任意矩形区域的值通过该展开式也能求解,所以我们可以暴力枚举每种以左上角(k,l)到右下角(i,j)的情况。
对于这个题边长是100,4层循环是10^8,因为循环并跑不了这么多,刚好也能卡过去。
代码如下:

#include <iostream>
#include"cstdio"
#include"string.h"
using namespace std;

const int N = 105;
int a[N][N];
int dp[N][N];
int ans[N][N];
int n,m;

int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF)
    {
    //初始化
        memset(a,0,sizeof(a));
        memset(dp,0,sizeof(dp));
        memset(ans,0,sizeof(ans));
        for(int i=0; i<=n; i++)
            for(int j=0; j<=n; j++)
                ans[i][j]=-12345678;
    //读图            
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                scanf("%d",&a[i][j]);
    //优化           
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+a[i][j];
    //暴力枚举
        for(int i=n; i>=1; i--)
            for(int j=n; j>=1; j--)
                for(int k=1; k<=i; k++)
                    for(int l=1; l<=j; l++)
                        ans[i][j]=max(ans[i][j],dp[i][j]-dp[i-k][j]-dp[i][j-l]+dp[i-k][j-l]);
    //找最大值                   
        int an=-12345678;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                an=max(an,ans[i][j]);
        printf("%d\n",an);
    }
    //fclose(stdin);
    return 0;
}

上面我们是枚举固定(i,j)移动(k,l)的情况,因为只要我们跑完了所有点,这4重循环的位置关系的改变并不影响结果,所以我们可以把四层for循环改成这样:

for(int i=n; i>=1; i--)
    for(int k=1; k<=i; k++)
        for(int j=n; j>=1; j--)
            for(int l=1; l<=j; l++)
                ans[i][j]=max(ans[i][j],dp[i][j]-dp[i-k][j]-dp[i][j-l]+dp[i-k][j-l]);

这里我们是先固定是矩形区域的上下边界,再枚举左右边界。这应该好理解,那么剩下我们该怎么优化呢。
当当我们的k=i+1的时候,我们求的是单排的最大连续矩形的和,可以看作一维数组的最大连续和,我们只需要O(n)的时间复杂度就能扫过去。
当我们要算k=i+2的时候,只需要把这个一位数组的值每项加上相应的列数,再一次O(n)又能求出这些结果。
由于k与i要枚举n^2,所以这种优化的方式时间复杂度是O(n^3)。

#include <iostream>
#include"cstdio"
#include"string.h"
#include"vector"
using namespace std;

const int N = 105;
const int INF = 1<<29;
int a[N][N];
int dp[N];
int sum[N];
int n,m;

int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF)
    {
        memset(a,0,sizeof(a));
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                scanf("%d",&a[i][j]);

        int ans=-INF;
        for(int i=1; i<=n; i++)
        {
        //每次改变上界限都要重置sum数组为0
            memset(sum,0,sizeof(sum));
            for(int j=i; j<=n; j++)
            {
                //下界限每次+1时把新加入的数加到sum数组中去
                for(int k=1;k<=n;k++)
                    sum[k]=sum[k]+a[j][k];
                //dp求解最大连续和,并随时更新ans
                for(int k=1;k<=n;k++)
                {
                     dp[k]=max(sum[k],dp[k-1]+sum[k]);
                     ans=max(ans,dp[k]);
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

第一种的用时和空间分别为:62MS 1696K
第二种的用时和空间分别为:15MS 1612K

版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU 1081 To The Max 暴力模拟O(n^4) dp优化O(n^3)

标签:动态规划

原文地址:http://blog.csdn.net/qq_27508477/article/details/47450615

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!