-
一个N*M的矩阵,找出这个矩阵中所有元素的和不小于K的面积最小的子矩阵(矩阵中元素个数为矩阵面积)
-
每个案例第一行三个正整数N,M<=100,表示矩阵大小,和一个整数K
接下来N行,每行M个数,表示矩阵每个元素的值
-
输出最小面积的值。如果出现任意矩阵的和都小于K,直接输出-1。
-
4 4 10 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
-
1
-
题目描述:
-
输入:
-
输出:
-
样例输入:
-
样例输出:
本题是一道非常好的题目,在我看来,所有动态规划解得题目都是十分精妙的。
首先,撇开题目不看,来做这样一道题,就是求一维数组里,大于等于给定任意正整数K的最短连续子序列的长度。
也就是说,这个数组里最短的连续多少个数加起来的值会超过K。这个问题,乍一看,会想到一个O(n*2)的解法,两个for循环搞定。
这里贴出一种DP解法,时间复杂度为O(n)
#include <iostream>
using namespace std;
int main(){ //找出数组a中大于等于K的最短连续子序列的长度
int a[4];
for(int i=0;i<4;i++)
cin>>a[i];
int K;
cin>>K;
int start = 0,end = 0;
int len = sizeof(a)/sizeof(int);
int ans = len + 1;
int sum = 0;
while(end < len){
if(sum < K)
sum += a[end];
while(sum >= K){
ans = min(ans,end-start+1);
sum -= a[start++]; //当出现和大于K时,start指针后移
}
end ++;
}
cout<<ans<<endl;
return 0;
}
大致思路是,用两个指针初始化指向头部,然后end指针逐渐后移,直到符合条件的子序列出现,记录当前的长度,然后前指针后移,直到sum<K,之后end指针继续后移。一遍下来就可以完成目标。
这里要注意的是,如果for循环里面的sum>=K,一次都没执行,说明所有的数加起来都没K大,特殊情况最好说明下。
好,至此,已经完成了所有的铺垫。
这道比较快捷的方法是,将高维数组降维,也就是说,选出任意两列,将这两列之间每行的元素相加,得到一个一维数组,对这个一维数组运用上面的最短连续子序列和的算法。时间为O(n),选择任意两列的时候,两个for循环,时间为O(n*2)
求出每种情况的子序列的 长度,得到方块数=(j-i+1)*findShorest(), 说明j表示第j列,i表示第i列(j>i)
对于每种情况的方块数,保留一个最小值即可。
#include <iostream>
#include <cstring>
using namespace std;
int matrix[110][110];
int num[110];
int N,M;
int K;
void merge(int i,int j){
for(int p=0;p<N;p++){
for(int k=i;k<=j;k++){
num[p] += matrix[p][k]; //合并成一维数组
}
}
}
int findShortest(){
int start = 0,end = 0;
int sum = 0;
int len = N;
int ans = len + 1;
bool flag = false;
while(end < len){
if(sum < K){
sum += num[end];
}
while(sum >= K){
flag = true;
ans = min(ans,end-start+1);
sum -= num[start++];
}
end ++;
}
if(flag)
return ans;
else
return N*M; //全部加起来值都没超过K
}
int main(){
while(cin>>N>>M){
cin>>K;
int sum = 0;
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
cin>>matrix[i][j];
sum += matrix[i][j];
}
}
if(sum < K)
cout<<-1<<endl;
else{
int min_element = N*M;
for(int i=0;i<M;i++){
for(int j=i;j<M;j++){
memset(num,0,sizeof(num));
merge(i,j);
int temp = findShortest();
temp = (j - i + 1) * temp;
if(temp < min_element)
min_element = temp;
}
}
cout<<min_element<<endl;
}
}
return 0;
}