题目描述
一个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
牛客网思路:
- 任选两列,把这两列间的元素相加成一列,即一维数组,实际宽度为 j - i + 1
- 遍历一维数组,找到和大于等于 K 的最短连续子序列,长度为 len
- 那么上面对应的子矩阵的面积为 (j - i + 1) * len
- 重复上述过程找到最小值
求一维数组里,大于等于给定任意正整数 K 的最短连续子序列的长度。我们可以用两个指针p、q初始化指向头部
如果sum[p~q]的和小于k,q向后移动;如果大于等于k,p向后移动;
在这个过程记录最小的 len=q-p+1
#include<iostream>
#include<stack>
#include<vector>
#include<map>
#include<string.h>
#include<queue>
#include<cmath>
using namespace std;
const int maxn = 110;
const int INF = 0x3fffffff;
int sum[maxn][maxn];
int com[maxn], min_len[maxn];
//把矩阵的第i行到第j行的每一列的和压缩到一个数组com
void compress(int i, int j,int m) {
com[0] = 0;
for (int u = 1; u <= m; u++) {
com[u] = (sum[j][u] - sum[i - 1][u]) + com[u - 1];
}
}
int main() {
int n, m, k;
int num;
while (cin >> n >> m >> k) {
memset(sum, 0, sizeof(sum));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> num;
sum[i][j] = sum[i - 1][j] + num;
}
}
int minlen = INF;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
compress(i, j, m);//二维之和压缩到一维
int p = 1, q = 1;
while (p <= m) { //求>=k的最短连续子串
if (com[q] - com[p - 1] >= k) {
minlen = min((q - p + 1)*(j - i + 1), minlen);
p++;
}
else if(q<=m){
q++;
}
else break;
}
}
}
if (minlen != INF)cout << minlen << endl;
else cout << -1 << endl;
}
return 0;
}