蓝桥-ALGO-44-采油区域

ACM模版

描述

描述
描述

题解

dp 问题,但是并不是单纯地 dp。

在这里,我们可以发现, KxK 的方阵只有三个,所以其组成的结构只有六种,分别是:左中右、上中下、左(右上)(右下)、(左上)(左下)右、上(左下)(右下)、(左上)(右上)下这六种,我们可以枚举所有格点,每个格点都可以将区域划分为上述六种,有的不合法就除去,剩下的合法状态中求最值就好了!

为了实现上述算法,需要求四个区域的最值,分别是左上角、右上角、左下角、右下角,十分繁琐的一道题,思路也不好想……

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

const int MAXN = 1555;

int N, M, K;
int map[MAXN][MAXN];
int sum[MAXN][MAXN];
int KK_sum[MAXN][MAXN];
int left_up[MAXN][MAXN];
int right_up[MAXN][MAXN];
int left_down[MAXN][MAXN];
int right_down[MAXN][MAXN];
int ans;

void get_sum()
{
    for (int i = 1; i <= N; i++)
    {
        for (int j = 1; j <= M; j++)
        {
            sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + map[i][j];
        }
    }
}

void get_KK_sum()
{
    for (int i = K; i <= N; i++)
    {
        for (int j = K; j <= M; j++)
        {
            KK_sum[i][j] = sum[i][j] - sum[i - K][j] - sum[i][j - K] + sum[i - K][j - K];
        }
    }
}

void get_dir_dir()
{
    for (int i = K; i <= N; i++)
    {
        for (int j = K; j <= M; j++)
        {
            left_up[i][j] = KK_sum[i][j];
            left_up[i][j] = max(left_up[i][j], left_up[i - 1][j]);
            left_up[i][j] = max(left_up[i][j], left_up[i][j - 1]);
        }
    }

    for (int i = K; i <= N; i++)
    {
        for (int j = M - K + 1; j; j--)
        {
            right_up[i][j] = KK_sum[i][j + K - 1];
            right_up[i][j] = max(right_up[i][j], right_up[i - 1][j]);
            right_up[i][j] = max(right_up[i][j], right_up[i][j + 1]);
        }
    }

    for (int i = N - K + 1; i; i--)
    {
        for (int j = K; j <= M; j++)
        {
            left_down[i][j] = KK_sum[i + K - 1][j];
            left_down[i][j] = max(left_down[i][j], left_down[i + 1][j]);
            left_down[i][j] = max(left_down[i][j], left_down[i][j - 1]);
        }
    }

    for (int i = N - K + 1; i; i--)
    {
        for (int j = M - K + 1; j; j--)
        {
            right_down[i][j] = KK_sum[i + K - 1][j + K - 1];
            right_down[i][j] = max(right_down[i][j], right_down[i + 1][j]);
            right_down[i][j] = max(right_down[i][j], right_down[i][j + 1]);
        }
    }
}

void get_ans()
{
    //  左 中 右 结构
    for (int j = K; j + (K << 1) <= M; j++)
    {
        for (int i = K; i <= N; i++)
        {
            int t = left_up[N][j] + KK_sum[i][j + K] + right_up[N][j + K + 1];
            ans = max(ans, t);
        }
    }

    //  上 中 下 结构
    for (int i = K; i + (K << 1) <= N; i++)
    {
        for (int j = K; j <= M; j++)
        {
            int t = left_up[i][M] + KK_sum[i + K][j] + left_down[i + K + 1][M];
            ans = max(ans, t);
        }
    }

    //  左 右上 右下 结构
    for (int j = K; j + K <= M; j++)
    {
        for (int i = K; i + K <= N; i++)
        {
            int t = left_up[N][j] + right_up[i][j + 1] + right_down[i + 1][j + 1];
            ans = max(ans, t);
        }
    }

    //  左上 左下 右 结构
    for (int j = K; j + K <= M; j++)
    {
        for (int i = K; i + K <= N; i++)
        {
            int t = left_up[i][j] + left_down[i + 1][j] + right_down[1][j + 1];
            ans = max(ans, t);
        }
    }

    //  上 左下 右下 结构
    for (int i = K; i + K <= N; i++)
    {
        for (int j = K; j + K <= M; j++)
        {
            int t = left_up[i][M] + left_down[i + 1][j] + right_down[i + 1][j + 1];
            ans = max(ans, t);
        }
    }

    // 左上 右上 下 结构
    for (int i = K; i + K <= N; i++)
    {
        for (int j = K; j + K <= M; j++)
        {
            int t = left_up[i][j] + right_up[i][j + 1] + left_down[i + 1][M];
            ans = max(ans, t);
        }
    }
}

int main()
{
    cin >> N >> M >> K;
    for (int i = 1; i <= N; i++)
    {
        for (int j = 1; j <= M; j++)
        {
            scanf("%d", map[i] + j);
        }
    }

    get_sum();
    get_KK_sum();
    get_dir_dir();

    ans = 0;
    get_ans();

    printf("%d\n", ans);

    return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值