最小面积子矩阵
题目描述
一个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\n", ans); } return 0; }
总结:此题的数据量虽然不大,但是采用常规方法遍历所有情况,容易超时。然后,我想到了排序,将所有元素排序然后再挑选~然而,如果是一个元素就能满足大于k的情况,不用排序,在输入数据时加入判断逻辑就好;如果大于1个元素才能满足情况,那么排序就打乱了矩阵元素的初始位置,后续的处理过程无法继续推进。
而参考的答案,采用逐行压缩累加的方式,巧妙遍历了所选子矩阵所有行的情况,然后在此基础上继续对每一列继续遍历,得到可能的列的取值。得到了子矩阵的行、列,于是可能的子矩阵最小面积就可以算出。可以说令人眼前一亮的是逐行累计压缩这种方式很新颖,此外之后对列的处理也需要使sum的值逼近k,才有可能得到最小的列数。