每个案例第一行三个正整数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
#include <iostream> using namespace std; int main() { int N,M,K; while(cin>>N>>M>>K){ int matrix[N][M]; for(int i=0;i<N;i++) for(int j=0;j<M;j++) cin>>matrix[i][j]; int minS=123123123; for(int i=0;i<N;i++){ int b[M]={0}; for(int j=i;j<N;j++){ int linecount=j-i+1; for(int k=0;k<M;k++) b[k]+=matrix[j][k]; int rowcount=0,k=0,temp=0; for(;k<M;k++){ temp+=b[k]; //temp为 从i~j行,rowcount~k列的总值 if(temp>=K){ //该子矩阵达到要求 if(minS>linecount*(k-rowcount+1)) //更新最小面积 minS=linecount*(k-rowcount+1); if(minS==1){ //已达到所能达到最小值,剪枝 printf("1\n"); return 0; } k=rowcount++; //从下一列开始从新计算 temp=0; } } } } if(minS==123123123) printf("-1\n"); else printf("%d\n",minS); } return 0; }
// 类似于求最大子矩阵和,O(n*m*m)#include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; const int AX = 1e2 + 66 ; int a[AX][AX]; int main() { int n , m , K , x ; scanf("%d%d%d",&n,&m,&K); memset( a , 0 , sizeof(a) ); for( int i = 1 ; i <= n ; i++ ) { for( int j = 1 ; j <= m ; j++ ) { scanf("%d",&a[i][j]); a[i][j] += a[i-1][j] ; } } int res = INF ; for( int i = 1 ; i <= n ; i++ ) { for( int j = 1 ; j <= m ; j++ ) { int sum = 0 ; int area = 0 ; for( int k = 1 ; k <= m ; k++ ) { int tmp = a[j][k] - a[i-1][k] ; if( ( sum < K && tmp <= 0 ) || ( sum >= K && tmp >= 0 ) ) { if( area ) k-- ; sum = 0 ; area = 0 ; } else { sum += tmp ; area += j - i + 1 ; if( sum >= K ) { res = min( res , area ) ; sum = 0 ; area = 0 ; } } } } } printf("%d\n",(res<INF?res:-1)); return 0 ; }
#include<iostream> (720)#include<algorithm> using namespace std; int m,n,k; int sumg[100][100] = { 0 }; //二维树状数组 注意树状数组下标从1开始 int sumr[100][100] = { 0 }; //子矩阵1,1到x,y的和,下标从1开始。下标为0的一律结果是0 int lowbit(int x) { return x & (-x); } void update(int a,int b,int c) { //更新二维树状数组 for (int i = a; i <= m; i += lowbit(i)) for (int j = b; j <= n; j += lowbit(j)) sumg[i][j] += c; } int getsum(int a, int b) { //通过树状数组求子矩阵 1,1到x,y的和。 int sum = 0; for (int i = a; i >0; i -= lowbit(i)) for (int j = b; j >0; j -= lowbit(j)) sum+=sumg[i][j]; return sum; } bool find(int a, int b) { //返回是否能找到一个高为a,长为b的矩阵,和满足>=K 。因为用已经计算好的数组sumr来算的,复杂度为O(m*n),常数项应该比较低 if (a > m)a = m; if (b > n)b = n; for (int i = 1; i <= m - a+1; i++) { for (int j = 1; j <= n - b+1; j++) { int tempsum = 0; tempsum = sumr[i+a-1][j+b-1] - sumr[i+a-1][j-1]- sumr[i -1][ j + b - 1]+sumr[i-1][j-1]; if (tempsum >=k)return 1; } } return 0; } int main() { int sum; cin >> m >> n >> k; for (int i = 1; i < m+1; i++){ //这个for整个复杂度 m*n*log(n)*log(m) sum = 0; for (int j = 1; j < n+1; j++) { int n; cin >> n; if (n >= k) { cout << 1; return 0; } //单个元素就比k大了,直接返回 update(i, j, n); //更新二维树状数组 } } for (int i = 1; i <= m; i++) { //这个for整个复杂度也是 m*n*log(n)*log(m) for (int j = 1; j <= n; j++) sumr[i][j] = getsum(i, j); } int maxmn = max(m, n); int face=-1; int min=0x3f3f3f3f; for (int i = 1; i <= maxmn; i++) { //这个for整个复杂度是i,j的m*n再乘以find的m*n复杂度,但是find的m*n常数项很低,故可以不超时。114ms for (int j = 1; j <= maxmn;j++) if (find(i, j) || find(j, 1)) { int temp = i * j; if (temp < min) { min = temp; face = temp; } break; } } cout<< face; return 0; }
#include <bits/stdc++.h> using namespace std; int n,m,k,a[110][110],ans,sum,minnum=1<<30; int GetMin(int tmp_array[]) { ans=1<<30; for(int i =0; i<n; i++) { sum=0; for(int j=i; j<n; j++) { sum+=tmp_array[j]; if(sum>=k) { if(ans>j-i+1) { ans=j-i+1; // cout<<ans<<" "<<sum<<" "<<j<<" "<<i<<endl; break; } } } } return ans; } int main() { //freopen("1.txt","r",stdin); cin>>n>>m>>k; for(int i=0; i<n; i++) for(int j=0; j<m; j++) cin>>a[i][j]; int tmp_array[110]; // for(int i=0; i<n; i++) // for(int j=0; j<m; j++) cout<<a[i][j]<<endl; for(int i=0; i<n; i++) { memset(tmp_array,0,sizeof(tmp_array)); for(int j=i; j<n; j++) { for(int t=0; t<m; t++) { tmp_array[t]+=a[j][t]; } // for(int z=0; z<n; z++) cout<<tmp_array[z]<<" "; // cout<<endl; int len=GetMin(tmp_array); if(len==1<<30) continue; // cout<<minnum<<" "<<j<<" "<<i<<" "<<len<<endl; minnum=min(minnum,len*(j-i+1)); } } cout<<minnum<<endl; return 0; }
//参考博客https://blog.csdn.net/Jaster_wisdom/article/details/52153685 #include <iostream> #define N 101 #define M 101 using namespace std; int Mat[N][M]; int temp[N][M]; int main() { int n,m,k; while(cin>>n>>m>>k){ int ans=123123123; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ cin>>Mat[i][j]; if(i==0){ temp[i][j]=Mat[i][j]; } else{ temp[i][j]=0; } } } for(int i=1;i<n;i++) for(int j=0;j<m;j++){ temp[i][j]=temp[i-1][j]+Mat[i][j];//将矩阵的每行的累加和用辅助矩阵temp进行存储 } int tmp[m]; for(int i=0;i<n;i++){ for(int j=i;j<n;j++){ for(int k=0;k<m;k++){ if(i==0) tmp[k]=temp[j][k]; else tmp[k]=temp[j][k]-temp[i-1][k]; } /* 求解一维数组中,和大于等于k的最短连续子序列的长度. 采用两个指针,一个指向当前处理的子序列的首部一个指向尾部。 ①如果当前序列的和小于k,end++ ②如果当前序列的和大于k,start++并减去首部的值 记录求解过程中出现的最短序列的长度 */ int sum=0; int start=0,end=0; while(end<m){ sum+=tmp[end]; while(sum>=k){ ans=min(ans,(end-start+1)*(j-i+1));//注意此处需要计算面积 sum-=tmp[start++]; } end++; } } } ans==123123123?cout<<-1<<endl:cout<<ans<<endl;//不存在输出-1 } return 0; } /* 4 4 100 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 */
/*最小面积子矩阵——元素和不小于k的面积的最小矩阵 思路:早上做了最大子矩阵这道题,学到压缩矩阵的方法(还是看保洁妹大佬的代码) 下午就尝试一下这个方法,真的是……不知道说些什么好啊,我是定义一个结构体,因为在想 那个行数的面积s的时候不可能每一个压缩矩阵都要共用一个s,所以就定义一个结构体保存每个压缩的 s如图 之后找最大连续子矩阵就 这部分代码 int sum=0; int s=0; for(j=0;j<m;j++){ if(sum<k){ sum+=buf[j].value; s+=buf[j].s; } } 说出来你们可能不信,我提交好几次才成功了,因为 if(sum>=k){ if(s<min_s){ min_s=s; } } 这部分代码,真的坑啊如果遍历完所有的压缩项依然小于k,那么最小的还是INF,如果不做判断,就会 出现INF变成某个数(因为累加的时候s+=buf[j].s),这里真的要注意啊 */#include<stdio.h>
#include<iostream> #include<cstdio> #include<algorithm> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<map> #include<set> #include<vector> #include<queue> #include<bitset> #include<ctime> #include<deque> #include<stack> #include<functional> #include<sstream> //#include<cctype> //#pragma GCC optimize(2) using namespace std; #define maxn 200005 #define inf 0x7fffffff //#define INF 1e18 #define rdint(x) scanf("%d",&x) #define rdllt(x) scanf("%lld",&x) #define rdult(x) scanf("%lu",&x) #define rdlf(x) scanf("%lf",&x) #define rdstr(x) scanf("%s",x) typedef long long ll; typedef unsigned long long ull; typedef unsigned int U; #define ms(x) memset((x),0,sizeof(x)) const long long int mod = 1e9; #define Mod 1000000000 #define sq(x) (x)*(x) #define eps 1e-5 typedef pair<int, int> pii; #define pi acos(-1.0) //const int N = 1005; #define REP(i,n) for(int i=0;i<(n);i++) typedef pair<int, int> pii; inline int rd() { int x = 0; char c = getchar(); bool f = false; while (!isdigit(c)) { if (c == '-') f = true; c = getchar(); } while (isdigit(c)) { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return f ? -x : x; } ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a%b); } int sqr(int x) { return x * x; } /*ll ans; ll exgcd(ll a, ll b, ll &x, ll &y) { if (!b) { x = 1; y = 0; return a; } ans = exgcd(b, a%b, x, y); ll t = x; x = y; y = t - a / b * y; return ans; } */ int n, m, K; int a[200][200]; bool fg; int pre[maxn]; int dp[maxn]; int minn = inf; void sol() { for (int i = 1; i <= n; i++) { ms(dp); for (int j = i; j <= n; j++) { ms(pre); for (int k = 1; k <= m; k++) dp[k] += a[j][k]; for (int k = 1; k <= m; k++)pre[k] = pre[k - 1] + dp[k]; int l = 1, r = 1; while (1) { if (r > m)break; while (pre[r] - pre[l - 1] < K&&r <= m)r++; if (pre[r] - pre[l - 1] >= K&&r<=m) { minn = min(minn, (j - i + 1)*(r - l + 1)); fg = 1; } while (pre[r] - pre[l - 1] >= K && l <= r) { minn = min(minn, (r - l + 1)*(j - i + 1)); l++; fg = 1; } } } } } int main() { //ios::sync_with_stdio(0); rdint(n); rdint(m); rdint(K); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++)rdint(a[i][j]); } sol(); if (fg == 0)cout << -1 << endl; else { cout << minn << endl; } return 0; }
#include <stdio.h> #include <limits.h> #define N 101 #define M 101 int martix[N][M];//输入的矩阵 int sum[M];//相邻的几行合并而成的一维数组 int m, n, k; int Shortest(int sum[M]) {//求一维数组里面和不小于k的最短连续序列长度 int from=0, to=0; int len=INT_MAX; int x=0;//from到to的序列和 while(to<m) { while(x<k&&to<m)//序列和小于k那终点后移 { x+=sum[to]; to++; } while(x>=k&&from<to-1)//序列和不小于k那起点后移 { if(to-from<len) len=to-from;//这是更短的序列,记下来 x-=sum[from]; from++; } if(from+1==to) return 1;//追尾了 } return len; } int main() { while(scanf("%d%d%d", &n, &m, &k)!=EOF) { for(int i=0; i<n; i++)//输入 { for(int j=0; j<m; j++) { scanf("%d", &martix[i][j]); } } int area=INT_MAX;//满足条件的最小面积,先假设是无穷大 for(int i=0; i<n; i++)//从i行开始合并 { for(int j=0; j<m; j++) sum[j]=0;//清空sum数组 for(int k=i; k<n; k++)//合并从i行到k行 { for(int j=0; j<m; j++) sum[j]+=martix[k][j]; int len=Shortest(sum); if(len!=INT_MAX) {//如果面积比已有的最小面积还小,那就修改最小面积 if(len*(k-i+1)<area) area=len*(k-i+1); } } } if(area==INT_MAX) printf("-1\n"); else printf("%d\n", area); } return 0; }
#include <iostream> #include <cmath> #include <cstring> #include <algorithm> #include <vector> #include <map> using namespace std; const int MAXN = 110; int arr[MAXN][MAXN] = {0}; int brr[MAXN][MAXN]; int main() { int n, m, k; while (cin >> n >> m >> k) { memset(arr, 0, sizeof arr); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cin >> brr[i][j]; } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { arr[i][j] = arr[i][j - 1] + arr[i - 1][j] + brr[i][j] - arr[i - 1][j - 1]; } } bool isOk = false; for (int i = 1; i <= n; i++) { // 宽 for (int j = 1; j <= m; j++) { // 长 for (int o = i; o <= n; o++) { for (int p = j; p <= m; p++) { if (arr[o][p] - arr[o - i][p] - arr[o][p - j] + arr[o - i][p - j] >= k ) { isOk = true; cout << i *j << endl; break; } } if (isOk) { break; } } if (isOk) { break; } } if (isOk) { break; } } if (!isOk) { cout << -1 << endl; } } return 0; }
#include <ios> #include<iostream> using namespace std; int m, n, k; int main(){ cin >> m >> n >> k; int matrix[m+1][n+1]; for(int i=0; i<m; ++i){ for(int j=0; j<n; ++j){ cin >> matrix[i+1][j+1]; if(matrix[i+1][j+1]>=k){ cout << 1; return 0; } } } for(int i=0; i<=m; ++i) matrix[i][0]=0; for(int j=0; j<=n; ++j) matrix[0][j]=0; // 添加第 0 行 0 列后,求和步骤可以和输入合并 for(int i=1; i<=m; ++i){ for(int j=1; j<=n; ++j){ matrix[i][j] += (matrix[i-1][j]+matrix[i][j-1]-matrix[i-1][j-1]); } } if(matrix[m][n]<k){ cout << -1; return 0; } // int l=1, w=1; int min_s=100001, loop_s=2; while(loop_s<=m*n){ for(int l=2; l<=loop_s && l<=m; ++l){ if(loop_s % l !=0 || loop_s/l>n) continue; int w=loop_s/l; for(int i=1; i+l-1<=m; ++i){ for(int j=1; j+w-1<=n; ++j){ int s=matrix[i+l-1][j+w-1] - matrix[i-1][j+w-1] - matrix[i+l-1][j-1] + matrix[i-1][j-1]; if(s>=k){ cout << loop_s; return 0; } } } } ++loop_s; } return 0; }
#include<iostream> #include<vector> #include<climits> using namespace std; int main(){ int n, m,k; cin >> n >> m >> k; vector<vector<int>> matrix(n, vector<int>(m, 0)); for(int i = 0;i < n;i++) for(int j = 0;j < m;j++) cin >> matrix[i][j]; int result = INT_MAX; for(int i = 0;i < n;i++){ vector<int> every(m); for(int j = i;j < n;j++){ //i,j遍历行区间 for(int k = 0;k < m;k++)//计算每列行区间元素之和 every[k] += matrix[j][k]; //----------------------以下是最小子数组的解法 int p = 0, sum = 0, result_per_loop = INT_MAX; for(int q = 0;q < m;q++){ sum += every[q]; while(sum >= k){ int sublength = q - p + 1; result_per_loop = result_per_loop > sublength ? sublength : result_per_loop; sum -= every[p++]; } } //------------------------ //不断比较获得最终结果 if(result_per_loop != INT_MAX){ int area = (j - i + 1) * result_per_loop; result = result > area ? area : result; } } } cout << (result == INT_MAX ? -1 : result) << endl; }
#include<bits/stdc++.h> using namespace std; const int maxn = 101; int n, m, k, matrix[maxn][maxn]; void init(){ for(int i = 0; i < n; i++){ for(int j = 0; j < m; j++){ cin>>matrix[i][j]; } } } void work(){ int area = INT32_MAX; for(int i = 0; i < n; i++){ vector<int> s(m, 0); for(int j = i; j < n; j++){ for(int a = 0; a < m; a++){ s[a] += matrix[j][a]; } // 此时已经得到了第 i 行与第 j 行之间每一列的和 s[k] // 可以用双指针或者说是滑动窗口来得到最小的矩形面积 int sum = s[0]; int low = 0, high = 1; // 左闭右开 while(high < m){ if(sum >= k){ area = min(area, (high - low) * (j - i + 1)); sum -= s[low]; low++; }else{ sum += s[high]; high++; } } } } if(area == INT32_MAX) area = -1; cout<<area<<endl; } int main(){ while(cin>>n>>m>>k){ init(); work(); } }
前缀和解法,理解简单,方法粗暴
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<vector> #include<string> using namespace std; const int MAXN = 103; int A[MAXN][MAXN]={0}; int minnum = MAXN*MAXN; int n,m,k; void judge(int a,int b){ for(int i=a;i<=n;i++){ for(int j=b;j<=m;j++){ int temp = A[i][j]-A[i][b-1]-A[a-1][j]+A[a-1][b-1]; if(temp>=k){ int numbers = (i-a+1)*(j-b+1); minnum = min(minnum,numbers); } } } } int main(){ cin>>n>>m>>k; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int temp; cin>>temp; A[i][j] = A[i][j-1]+A[i-1][j]-A[i-1][j-1]+temp; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ judge(i, j); } } if(minnum==MAXN*MAXN){ minnum = -1; } cout<<minnum<<endl; return 0; }
#include<bits/stdc++.h> using namespace std; int n,m,K;//n为行数 m为列数 int ma[100][100];//matrix int me[100];//merge int mArea=INT_MAX;//最小面积 int main(){ while(cin>>n>>m>>K){ for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ cin>>ma[i][j]; } } for(int i=0;i<n;i++){ for(int j=i;j<n;j++){//从第i行到第j行的子矩阵 memset(me,0,sizeof(me)); for(int k=0;k<m;k++){//从首列到最后一列依次merge for(int l=i;l<=j;l++){//每列的第i行到第j行依次merge me[k]+=ma[l][k]; } } //至此 从第i行到第j行的merge结束 //接下来要研究merge的连续子序列了 //其中 j-i+1 为子矩阵的行数 for(int k=0;k<m;k++){ //从merge[k]出发的子序列 //l-k+1 为子矩阵列数 int sum=0; for(int l=k;l<m&&(j-i+1)*(l-k+1)<=mArea;l++){ sum+=me[l]; if(sum>=K){//当前子序列超过K了就别再往后看了 mArea=(j-i+1)*(l-k+1); break; } } } } } if(mArea==INT_MAX) cout<<"-1"<<endl; else cout<<mArea<<endl; } }
#include<iostream> #include<algorithm> #include<cmath> #include<cstring> using namespace std; int main() { int n,m,x; while(cin>>n>>m>>x) { int h[110][110]; int b[110]; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { cin>>h[i][j]; } } int dp[110][110]; for(int i=0; i<m; i++) dp[0][i]=h[0][i]; for(int i=1; i<n; i++) { for(int j=0; j<m; j++) { dp[i][j]=dp[i-1][j]+h[i][j]; } } int minx=99999999; for(int i=0; i<n; i++) { for(int j=i; j<n; j++) { for(int o1=0; o1<m; o1++) { int num=0; for(int k=o1; k<m; k++) { if(i==0) b[k]=dp[j][k]; else b[k]=dp[j][k]-dp[i-1][k]; num+=b[k]; if(num>x){ int sum=(j-i+1)*(k-o1+1); if(sum<minx) minx=sum; } } } } } cout<<minx<<endl; } return 0; }
#include <iostream> #include <string> #include <vector> #include <limits.h> int MinArea(std::vector<std::vector<int>>& matrix, int n, int m, int k){ std::vector<std::vector<int>> tmp; for (int i = 0; i < n; i++){ tmp.push_back(std::vector<int>(m, 0)); } int min_area = INT_MAX; for (int rows = 1; rows <= n; rows++){ for (int i = n-1; i-rows+1 >= 0; i--){ for (int j = 0; j < m; j++){ tmp[i][j] = tmp[i][j] + matrix[i-rows+1][j]; } int left = 0; int right = 0; int sum = 0; while(left < m && right < m+1){ if (sum < k){ sum = sum + tmp[i][right]; right++; }else{ if ((right-left)*rows < min_area){ min_area = (right-left)*rows; } sum = sum - tmp[i][left]; left++; } } } } return min_area; } int main(){ std::string N, M, K; std::string V; while(std::cin >> N >> M >> K){ int n = std::stoi(N); int m = std::stoi(M); int k = std::stoi(K); std::vector<std::vector<int>> matrix; for (int i = 0; i < n; i++){ std::vector<int> row; for (int j = 0; j < m; j++){ std::cin >> V; row.push_back(std::stoi(V)); } matrix.push_back(row); } int min_area = MinArea(matrix, n, m, k); std::cout << min_area << std::endl; } return 0; }
#include<iostream> #include<climits> #include<algorithm> #include<cstring> using namespace std; int N, M, K; int** arr; void init() { arr = new int* [N + 1]; for (int i = 0; i <= N; i++) { arr[i] = new int[M + 1]; fill(arr[i], arr[i]+M+1, 0); } for (int i = 1; i <= N; i++) { for (int j = 1; j <= M; j++) { cin >> arr[i][j]; arr[i][j] += arr[i - 1][j]; } } } // 获取从i到j行的行相加的压缩一维数组 int* getSubArr(int i, int j) { int* subArr = new int[M + 1]; fill(subArr, subArr+M+1, 0); for (int k = 1; k <= M; k++) { subArr[k] = arr[j][k] - arr[i][k]; } return subArr; } int main() { while (cin >> N >> M >> K) { init(); int minArea = INT_MAX; bool flag = false; for (int i = 0; i < N; i++) { for (int j = i + 1; j <= N; j++) { int* subArr = getSubArr(i, j); int* subArrCopy = new int[M + 1]; int* begin = new int[M + 1]; fill(begin, begin+M+1, 0); for (int t = 0; t <= M; t++) { begin[t] = t; subArrCopy[t] = subArr[t]; } for (int k = 1; k <= M; k++) { if (subArr[k] >= K) { minArea = min(minArea, j - i); flag = true; continue; } if (subArr[k - 1] + subArr[k] > subArr[k]) { subArr[k] = subArr[k - 1] + subArr[k]; begin[k] = begin[k - 1]; if (subArr[k] >= K) { int sum = 0; for (int u = k; u >= begin[k]; u--) { sum += subArrCopy[u]; if (sum >= K) { minArea = min(minArea, (j - i) * (k - u + 1)); flag = true; break; } } } } } } } if (!flag) { cout << -1 << endl; } else { cout << minArea << endl; } } return 0; }