zoukankan      html  css  js  c++  java
  • HihoCoder 1634 Puzzle Game(最大子矩阵和)题解

    题意:给一个n*m的矩阵,你只能选择一个格子把这个格子的数换成p(也可以一个都不换),问最大子矩阵和最小可能是多少?

    思路:

    思路就是上面这个思路,这里简单讲一下怎么n^3求最大子矩阵和:枚举两行(或者两列),然后把每一列之和看做一个数字,这样二维就变成了一维,我们可以直接求最大子串和的方法。初始一个ret为0,然后从左往右加,如果ret<0,那么把ret初始化0,负数作为初始值肯定比重新开始小,然后找出ret的最大值就是最大子矩阵和。

    代码:

    #include<cstdio>
    #include<cstring>
    typedef long long ll;
    using namespace std;
    const int maxn = 150 + 10;
    const int MOD = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    int num[maxn][maxn], sum[maxn][maxn];
    int up[maxn], down[maxn], left[maxn], right[maxn];
    int n, m, p, xx1, yy1, xx2, yy2;
    int min(int x, int y){
        return x < y? x : y;
    }
    int max(int x, int y){
        return x > y? x : y;
    }
    int mat(int x1, int y1, int x2, int y2){
        return sum[x2][y2] - sum[x1 - 1][y2] - sum[x2][y1 - 1] + sum[x1 - 1][y1 - 1];
    }
    int main(){
        while(~scanf("%d%d%d", &n, &m, &p)){
            memset(sum, 0, sizeof(sum));
            for(int i = 1; i <= n; i++){
                for(int j = 1; j <= m; j++){
                    scanf("%d", &num[i][j]);
                    sum[i][j] = num[i][j] + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
                }
            }
    
            //上下左右四个矩阵预处理
            memset(up, -INF ,sizeof(up));
            for(int i = 1; i <= n; i++){
                int tmp = -INF;
                for(int j = 1; j <= i; j++){
                    int ret = 0;
                    for(int k = 1; k <= m; k++){
                        ret += mat(j, k, i, k);
                        tmp = max(tmp, ret);
                        if(ret < 0) ret = 0;
                    }
                }
                up[i] = max(up[i - 1], tmp);
            }
            memset(down, -INF, sizeof(down));
            for(int i = n; i >= 1; i--){
                int tmp = -INF;
                for(int j = i; j <= n; j++){
                    int ret = 0;
                    for(int k = 1; k <= m; k++){
                        ret += mat(i, k, j, k);
                        tmp = max(tmp, ret);
                        if(ret < 0) ret = 0;
                    }
                }
                down[i] = max(down[i + 1], tmp);
            }
            memset(left, -INF, sizeof(left));
            for(int i = 1; i <= m; i++){
                int tmp = -INF;
                for(int j = 1; j <= i; j++){
                    int ret = 0;
                    for(int k = 1; k <= n; k++){
                        ret += mat(k, j, k, i);
                        tmp = max(ret, tmp);
                        if(ret < 0) ret = 0;
                    }
                }
                left[i] = max(left[i - 1], tmp);
            }
            memset(right, -INF, sizeof(right));
            for(int i = m; i >= 1; i--){
                int tmp = -INF;
                for(int j = i; j <= m; j++){
                    int ret = 0;
                    for(int k = 1; k <= n; k++){
                        ret += mat(k, i, k, j);
                        tmp = max(ret, tmp);
                        if(ret < 0) ret = 0;
                    }
                }
                right[i] = max(right[i + 1], tmp);
            }
    
            int Max = -INF;
            for(int i = 1; i <= n; i++){
                for(int j = 1; j <= i; j++){
                    int ret = 0, start = 1;;
                    for(int k = 1; k <= m; k++){
                        ret += mat(j, k, i, k);
                        if(ret > Max){
                            Max = ret;
                            xx1 = j, yy1 = start, xx2 = i, yy2 = k;
                        }
                        if(ret < 0) ret = 0, start = k + 1;
                    }
                }
            }
            int ans = Max;
            for(int i = xx1; i <= xx2; i++){
                for(int j = yy1; j <= yy2; j++){
                    if(p > num[i][j]) continue;
                    ans = min(ans , max(Max - num[i][j] + p, max(up[i - 1], max(down[i + 1], max(left[j - 1], right[j + 1])))));
                }
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    c++ 编译时检测结构体大小的的宏定义写法
    文本格式转换的网站,云转换
    chm格式文件,win7下用c:/windows/hh.exe打开
    visual paradigm 自动解析代码生成 UML图
    proxifiler 代理神器
    linux下设置 git ssh 代理
    一直出现 Enter passphrase for key '/root/.ssh/gitkey12.pub'
    connect-proxy rpm文件的安装
    [转] ssh免密码登录服务器
    [转] 公司局域网中代码访问 github.com
  • 原文地址:https://www.cnblogs.com/KirinSB/p/10301669.html
Copyright © 2011-2022 走看看