NOI1768:最大子矩阵

本文介绍了两种求解最大子矩阵问题的算法:暴力求解和动态规划(dp)方法。暴力求解通过四层循环遍历所有可能的子矩阵,复杂度为O(n^4)。dp方法使用前缀和和类似最大连续子串的算法,将复杂度降低到O(n^3)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

1768:最大子矩阵

题解

暴力求解

题目范围为 0 &lt; N &lt; = 100 0 &lt; N &lt;= 100 0<N<=100,可以直接暴力求解最大子矩阵。复杂度为 O ( n 4 ) O(n^4) O(n4),这个复杂度一般是可以接受的。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define maxn 105
#define inf 0x3f3f3f3f

int n, ans;
int f[maxn][maxn], a[maxn][maxn];

int _max(int a, int b){
    return a > b ? a : b;
}
int main()
{
    scanf("%d", &n);
    ans = -inf;
    int i, j, k, l;
    for(i = 1; i <= n; i++){
        for(j = 1; j <= n; j++){
            scanf("%d", &a[i][j]);
            f[i][j] = f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1] + a[i][j];
        }
    }
    for(i = 1; i <= n; i++){
        for(j = 1; j <= n; j++){
            for(k = i; k <= n; k++){
                for(l = j; l <= n; l++){
                    ans = _max(ans, f[k][l] - f[k][j - 1] - f[i - 1][l] + f[i - 1][j - 1]);
                }
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}
dp求解
  • p r e [ i ] [ j ] pre[i][j] pre[i][j] 表示对于第 j j j 列,前 i i i 行的矩阵前缀和。即 p r e [ i ] [ j ] = ∑ k = 1 i a [ k ] [ j ] pre[i][j] = \sum_{k = 1}^{i}a[k][j] pre[i][j]=k=1ia[k][j]
  • f [ k ] f[k] f[k] 表示对于起始行号为 i i i,终止行号为 j j j的子矩阵,子矩阵第 j j j 列的元素之和。

利用类似于求解最大连续子串的方法对 f [ k ] f[k] f[k] 进行求解。所得即为最大子矩阵,复杂度为 O ( n 3 ) O(n ^3) O(n3)

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define maxn 105
#define inf 0x3f3f3f3f

int n, ans;
int pre[maxn][maxn], a[maxn][maxn], f[maxn];

int _max(int a, int b){
    return a > b ? a : b;
}
int main()
{
    scanf("%d", &n);
    ans = -inf;
    int i, j, k;
    for(i = 1; i <= n; i++){
        for(j = 1; j <= n; j++){
            scanf("%d", &a[i][j]);
            pre[i][j] = pre[i - 1][j] + a[i][j];
        }
    }
    for(i = 1; i <= n; i++){
        for(j = i + 1; j <= n; j++){
            for(k = 1; k <= n; k++){
                f[k] = pre[j][k] - pre[i - 1][k];
            }
            for(k = 1; k <= n; k++){
                f[k] = _max(f[k - 1] + f[k], f[k]);
                ans = _max(ans, f[k]);
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值