zoukankan      html  css  js  c++  java
  • 【APIO2009T1】采油区域-分类讨论+动态规划

    测试地址:采油区域
    题目大意:给定一个M×N的仅含非负整数的矩阵,要求找出三个不相交的K×K区域使区域内整数之和最大,输出这个最大值。
    做法:这道题目需要用到分类讨论+动态规划。
    因为不能相交,所以三个正方形区域的位置关系一定可以被归为下列情况之一:
    1.三个正方形被一条横向的分界线间隔,可能的情况有:
    (1)上面有两个,下面有一个。
    (2)上面有一个,下面有两个。
    2.三个正方形被一条纵向的分界线间隔,可能的情况有:
    (1)左边有两个,右边有一个。
    (2)左边有一个,右边有两个。
    而在同一个区域的两个正方形要么被一条横向的分界线间隔,要么被一条纵向的分界线间隔。因此,我们只需枚举分界线,按照这种方法分割区域后,每个区域再找出一个最大的正方形即可。
    枚举分界线是O(MN)的,但如果暴力算一个区域内的最大正方形,复杂度是O(K2MN)的,绝对会炸。这时候就要想办法预处理出一些区域内最大的正方形。首先我们可以对矩阵求一个二维前缀和,然后算正方形就是O(1)的了,而我们发现,上面那些情况中,要求的区域只有6种情况:4种角上的区域,还有2种是被两条分界线隔在中间的区域。前面4种预处理就很容易了,而后面2种实际上不用完全预处理完,我们可以求出正方形右下角点在某一行(列)上时最大的正方形值,这样在枚举分界线时就可以顺便计算出某个区域中最大的正方形值。
    由于没有图,我也解释不太清楚了,详细看代码吧。优化后的算法复杂度为O(MN),可以说是完美的复杂度。
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    using namespace std;
    int n,m,k;
    ll map[1510][1510],sum[1510][1510]={0},bsum[1510][1510]={0};
    ll mx1[1510][1510]={0},mx2[1510][1510]={0},mx3[1510][1510]={0},mx4[1510][1510]={0};
    ll mx5[1510]={0},mx6[1510]={0};
    ll ans=0;
    
    int main()
    {
        scanf("%d%d%d",&m,&n,&k);
        for(int i=1;i<=m;i++)
        {
            int tot=0;
            for(int j=1;j<=n;j++)
            {
                scanf("%lld",&map[i][j]);
                tot+=map[i][j];
                sum[i][j]=sum[i-1][j]+tot;
            }
        }
        for(int i=k;i<=m;i++)
            for(int j=k;j<=n;j++)
                bsum[i][j]=sum[i][j]-sum[i-k][j]-sum[i][j-k]+sum[i-k][j-k];
        for(int i=k;i<=m;i++)
        {
            ll mx=0;
            for(int j=k;j<=n;j++)
            {
                mx=max(mx,bsum[i][j]);
                mx1[i][j]=max(mx1[i-1][j],mx);
            }
        }
        for(int i=m;i>=k;i--)
        {
            ll mx=0;
            for(int j=n;j>=k;j--)
            {
                mx=max(mx,bsum[i][j]);
                mx2[i][j]=max(mx2[i+1][j],mx);
            }
        }
        for(int i=k;i<=m;i++)
        {
            ll mx=0;
            for(int j=n;j>=k;j--)
            {
                mx=max(mx,bsum[i][j]);
                mx3[i][j]=max(mx3[i-1][j],mx);
            }
        }
        for(int i=m;i>=k;i--)
        {
            ll mx=0;
            for(int j=k;j<=n;j++)
            {
                mx=max(mx,bsum[i][j]);
                mx4[i][j]=max(mx4[i+1][j],mx);
            }
        }
        for(int i=k;i<=m;i++)
            for(int j=k;j<=n;j++)
                mx5[i]=max(mx5[i],bsum[i][j]);
        for(int j=k;j<=n;j++)
            for(int i=k;i<=m;i++)
                mx6[j]=max(mx6[j],bsum[i][j]);
        for(int i=k;i<=m-k;i++)
            for(int j=k;j<=n-k;j++)
            {
                ans=max(ans,mx1[i][j]+mx2[i+k][k]+mx3[i][j+k]);
                ans=max(ans,mx1[m][j]+mx2[i+k][j+k]+mx3[i][j+k]);
                ans=max(ans,mx1[i][n]+mx2[i+k][j+k]+mx4[i+k][j]);
                ans=max(ans,mx1[i][j]+mx2[k][j+k]+mx4[i+k][j]);
            }
        ll mmx1=0,mmx2;
        for(int i=k;i<=m-2*k;i++)
        {
            mmx1=max(mmx1,mx5[i]);
            mmx2=0;
            for(int j=i+k;j<=m-k;j++)
            {
                mmx2=max(mmx2,mx5[j]);
                ans=max(ans,mmx1+mmx2+mx2[j+k][k]);
            }
        }
        mmx1=0;
        for(int i=k;i<=n-2*k;i++)
        {
            mmx1=max(mmx1,mx6[i]);
            mmx2=0;
            for(int j=i+k;j<=n-k;j++)
            {
                mmx2=max(mmx2,mx6[j]);
                ans=max(ans,mmx1+mmx2+mx2[k][j+k]);
            }
        }
        printf("%lld",ans);
    
        return 0;
    }
    
  • 相关阅读:
    spring的工厂类
    spring的基于XML方式的属性注入
    github上传大于100M的文件报错
    fatal: HttpRequestException encountered
    VAR 学习笔记3
    You are my great sunshine
    warning: LF will be replaced by CRLF in
    术语词汇
    XGBoost学习笔记2
    四大基本算法思想
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793600.html
Copyright © 2011-2022 走看看