最小面积子矩阵

Posted heyour

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小面积子矩阵相关的知识,希望对你有一定的参考价值。

题目描述

一个N*M的矩阵,找出这个矩阵中所有元素的和不小于K的面积最小的子矩阵(矩阵中元素个数为矩阵面积)

输入描述:

每个案例第一行三个正整数N,M<=100,表示矩阵大小,和一个整数K
接下来N行,每行M个数,表示矩阵每个元素的值

输出描述:

输出最小面积的值。如果出现任意矩阵的和都小于K,直接输出-1。
示例1

输入

4 4 10
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16

输出

1

 

参考链接:最小面积子矩阵

最终AC代码:

#include <bits/stdc++.h>
using namespace std;
const int MAX=105;
int n, m, k, temp[MAX], re[MAX][MAX];
int getMin(){
    int i, j, sum=0, ans=-1;
    for(i=0, j=0; i<m; i++){
        sum += temp[i];
        if(sum >= k){ //sum满足
            while(sum-temp[j] >= k){ //尝试逼近k 从而减少元素个数
                j++;
                sum -= temp[j];
            }
            if(ans=-1 || ans>i-j+1) ans = i - j + 1;
        }
    }
    return ans;
}
int main(){
    int i, j, l, t, ans;
    while(cin >> n >> m >> k){
        for(i=0; i<n; i++){
            for(j=0; j<m; j++) scanf("%d", &re[i][j]);
        }
        ans = -1;
        for(i=0; i<n; i++){ //i表示起始行数
            memset(temp, 0, sizeof(temp));
            for(j=i; j<n; j++){ //逐行累加 且 每次累加后都进行一次判断
                for(l=0; l<m; l++) temp[l] += re[j][l]; //对应列相加
                t = getMin(); //t保存的其实是最小列数
                if(t < 0) continue; //表示不满足要求
                if(ans==-1 || ans>t*(j-i+1)) ans = t * (j-i+1); //j-i+1表示最小行数
            }
        }
        printf("%d
", ans);
    }
    return 0;
}

总结:此题的数据量虽然不大,但是采用常规方法遍历所有情况,容易超时。然后,我想到了排序,将所有元素排序然后再挑选~然而,如果是一个元素就能满足大于k的情况,不用排序,在输入数据时加入判断逻辑就好;如果大于1个元素才能满足情况,那么排序就打乱了矩阵元素的初始位置,后续的处理过程无法继续推进。

而参考的答案,采用逐行压缩累加的方式,巧妙遍历了所选子矩阵所有行的情况,然后在此基础上继续对每一列继续遍历,得到可能的列的取值。得到了子矩阵的行、列,于是可能的子矩阵最小面积就可以算出。可以说令人眼前一亮的是逐行累计压缩这种方式很新颖,此外之后对列的处理也需要使sum的值逼近k,才有可能得到最小的列数。

以上是关于最小面积子矩阵的主要内容,如果未能解决你的问题,请参考以下文章

1102.最小子面积矩阵

SPOJ MINSUB - Largest Submatrix(二分+单调栈)

51nod 1158 全是1的最大子矩阵(单调栈 ,o(n*m))

HDOJ6957Maximal submatrix(单调栈,最大子矩阵面积)

dp:最大子矩阵面积

hdu 1506 最大子矩阵面积