1 条题解

  • 0
    @ 2025-5-6 16:35:03

    解题思路分析 目标:找到一个大小至少为 R 行和 C 列的子矩阵,使得该子矩阵中数字的平均值最大化。 关键思路: 由于暴力枚举所有可能的子矩阵会导致时间复杂度太高(时间限制超出),所以采用优化的方法。 利用前缀和数组 sum 来快速计算子矩阵的元素和。对于矩阵 a,sum[i][j] 表示从矩阵左上角 (0, 0) 到 (i, j) 位置的子矩阵的元素和。 通过枚举不同的起始行 baseline 和结束行 endline(保证子矩阵行数至少为 R),在每一对起始行和结束行确定的范围内,对每一列计算在这个行范围内的子数组(子矩阵的列方向),利用 getmost 函数找到密度最大的至少 C 列的子数组。 getmost 函数通过滑动窗口的思想,维护一个队列来处理子数组的元素,从而高效地计算出密度最大的子数组。

    实现步骤 输入矩阵信息: 读取矩阵的行数 m、列数 n、约束子矩阵的行数 r 和列数 c。 依次读取矩阵 a 的每一个元素。 计算前缀和数组: 首先初始化 sum[0][i] 为 a[0][i]。 然后对于 i > 0 的情况,通过 sum[i][j] = a[i][j] + sum[i-1][j] 计算每一个位置的前缀和。 枚举起始行和结束行: 从 baseline = 0 开始枚举,直到 baseline + r - 1 < m(保证子矩阵行数至少为 r)。 当 baseline > 0 时,对 sum 数组进行更新,将当前行范围以上的元素和减去,即 sum[i][j] -= a[baseline - 1][j],这样 sum 数组在当前行范围内就表示相对独立的子矩阵的前缀和。 在当前行范围内枚举列方向的子数组: 对于每一个结束行 endline(endline >= baseline + r - 1),调用 getmost 函数,传入 sum[endline](表示当前结束行的列方向数组)、列数 n、当前行范围内的行数 endline - baseline + 1,以及用于记录子数组起始和结束位置的变量 st 和 ed。

    getmost 函数通过滑动窗口和队列维护,计算出在当前行范围内,列方向上密度最大的至少 C 列的子数组。 记录最优子矩阵: 如果当前计算得到的子矩阵密度 t 大于之前记录的最优密度 res,则更新 res 以及最优子矩阵的起始行 str、起始列 stc、结束行 edr 和结束列 edc。 输出结果: 输出最优子矩阵的左上角和右下角的索引(注意索引要加 1 以符合题目要求的从 1 开始计数)。 当所有矩阵处理完后,输出 * 表示输入结束。 getmost 函数分析 功能:在给定的数组 a 中,找到长度至少为 c 且密度最大的子数组,返回其密度,并记录子数组的起始位置 st 和结束位置 ed。

    实现步骤: 初始化变量 s 用于记录当前子数组的元素和,ii 用于辅助,res 用于记录最大密度,q 是一个队列。 先将前 c 个元素加入队列,并计算它们的和 s 以及初始密度 res,同时记录子数组的起始和结束位置。 从第 c 个元素开始遍历数组,每次将新元素 t 加入队列,更新元素和 s。 如果当前子数组密度大于 res,则更新 res 和子数组的起始和结束位置。 如果队列长度大于等于 c 且队首元素小于等于当前元素 t,则不断弹出队首元素,更新元素和 s,如果弹出后子数组密度大于 res,则更新 res 和子数组的起始和结束位置。

    #include<iostream>
    #include<queue>
    using namespace std;
    
    int m,n,r,c;
    int a[250][250], sum[250][250];
    
    double getmost(int *a, int len, int lines, int &st, int &ed){
        int s = 0, ii = 0;
        double res;
        queue<int> q;
        for(int i =0; i < c; i++)
                res+=a[i], s+=a[i], q.push(a[i]);
        
        res = s/(c*lines*1.0);
        st = 0, ed = c-1;
        for(int i = c; i < len; i++){
                int t = a[i];
                q.push(a[i]);
                int l = q.size();
                s+=t;
                if(s/(lines*l*1.0)>res)
                                 res = s/(lines*l*1.0), st = i-l+1, ed = i;
                while(q.size()>=c&&t>=q.front()){
                                                 s-=q.front();
                                                 l--;
                                                 q.pop();
                                                 if(s/(lines*l*1.0)>res)
                                                                  res = s/(lines*l*1.0), st = i-l+1, ed = i;
                }
        }
        return res;
    }
        
    
    int main(){
        while(cin>>m&&m){
                         cin >> n >> r  >> c;
                         for(int i = 0; i < m; i++)
                                 for(int j = 0; j < n; j++)
                                         cin >> a[i][j];
                         for(int i = 0; i < n; i++)
                                 sum[0][i]=  a[0][i];
                         for(int i = 1; i < m; i++)
                                 for(int j = 0; j < n; j++)
                                         sum[i][j] = a[i][j]+sum[i-1][j];
                         double res = 0;
                         int str, stc, edr, edc;
                         for(int baseline = 0; baseline+r-1<m; baseline++){
                                 if(baseline>0){
                                                for(int i = baseline; i < m; i++)
                                                        for(int j = 0; j < n; j++)
                                                                sum[i][j]-=a[baseline-1][j];
                                 }
                                 int st,ed;
                                 for(int endline = baseline+r-1; endline<m; endline++){
                                         double t = getmost(sum[endline],n,endline-baseline+1,st,ed);
                                         //cout <<baseline << ' ' << endline << ' ' << st << ' ' << ed << ' '<<t << endl;
                                         if(res<t){
                                                   res = t;
                                                   str = baseline, stc = st, edr = endline, edc = ed;
                                         }
                                 }
                         }
                         cout << str+1 << ' ' << stc+1 << ' '  << edr+1 << ' '<< edc+1 << endl;
               }
               cout << '*' << endl;
    }
    • 1

    信息

    ID
    388
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者