题意
给出n行m列的矩阵,求由 1 组成的第二大矩形面积,如果1矩阵不足2个,输出0。
题解
将每列相邻的1看成一个宽为1的矩形,然后向左(右)扩展
超时,通过率为97.62%(虽然超时,但思想很好理解,理解这个之后,下面AC代码剪枝)
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
int dp[1005][1005];
int secArea = -1, maxArea = -1;
int main(){
int n,m;
memset(dp,0,sizeof(dp));
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%1d", &dp[i][j]);
dp[i][j] += dp[i][j] * dp[i-1][j]; // 处理列,表示矩形高
}
}
for(int i = 1; i<= n; i++){
for(int j = 1; j<= m; j++){
int height = dp[i][j];
int wide = 1;
while(height){
int Area = height * wide; // 矩形面积,宽和高
if(Area > maxArea){ // 判断面积是否第二
secArea = maxArea;
maxArea = Area;
}
else if(Area > secArea){
secArea = Area;
}
height = min(height,dp[i][j-wide]); // 矩形的高为此行的最低,意思是短板
wide++; // 矩形向右平移
}
}
}
printf("%d\n",(secArea == -1 ? 0 : secArea));
return 0;
}
AC代码(同样的思路,从后往前,可以剪枝,很快)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[1005][1005];
int main(){
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%1d", &a[i][j]);
a[i][j] += a[i][j] * a[i-1][j]; // 矩形高度
}
}
int maxarea = 0, secarea = 0;
for(int i = n; i >= 1; i--){
for(int j = m; j >= 1; j--){
int height = a[i][j];
for(int k = j; k >= 0; k--){
if(a[i][k] == 0){ // 如果这列的矩形高度为0,因为短板定理,所以直接退出循环
break;
}
if(height * j <= secarea){ // 这里剪枝,高度*宽度小于第二大面积,那么往前走
break; // 高度有可能会变低,所以之前的矩形会越来越小
}
height = min(height, a[i][k]);
int area = height * (j-k+1); // 宽度
if(area >= maxarea){
secarea = maxarea;
maxarea = area;
}
else if(area >= secarea){
secarea = area;
}
}
}
}
printf("%d\n", secarea);
return 0;
}