这是某dalao用长度来求解的
//悬线法
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 2005
using namespace std;
int n,m,a[maxn][maxn],ans1,ans2;
int h[maxn][maxn],r[maxn][maxn],l[maxn][maxn];
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') {if(c=='-')f=-1;c=getchar();}
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
void pre(){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(a[i][j]^a[i][j-1]) l[i][j]=l[i][j-1]+1;
if(a[i][m-j+1]^a[i][m-j+2]) r[i][m-j+1]=r[i][m-j+2]+1;
if(a[i][j]^a[i-1][j]) h[i][j]=h[i-1][j]+1;
}
}
int main(){
n=rd(); m=rd();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]=rd();
pre();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(h[i][j]){
l[i][j]=min(l[i][j],l[i-1][j]);
r[i][j]=min(r[i][j],r[i-1][j]);
}
int tmp=min(h[i][j]+1,(l[i][j]+r[i][j]+1));
ans1=max(ans1,tmp*tmp);
ans2=max(ans2,(h[i][j]+1)*(l[i][j]+r[i][j]+1));
}
printf("%d\n%d",ans1,ans2);
return 0;
}
这是把问题转换为求最大全0子矩阵或最大全1子矩阵的问题求解
方法是 ==改变棋盘把行数+列数为奇数或偶数的位置异或 ==
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2010, M=2010;
int n,m;
int a[N][M],ri[N][M];
int ans1,ans2;
int topl[M],topr[M],up[M];
inline void getans(){
memset(up,0,sizeof(up));
int i,j,nowl,nowr,lin;
for(j=1; j<=m; ++j){ topl[j]=1; topr[j]=m; }
for(i=1; i<=n; ++i){ // 一行一行地刷新帘子
nowl=0; nowr=m+1;
for(j=1; j<=m; ++j){ // 从左到右更新左端点
if(a[i][j]){
up[j]=0;
topl[j]=1;
nowl = j;
}else{
up[j]++;
topl[j] = max(topl[j], nowl+1);
}
}
for(j=m; j>=1; --j){ // 从右到左更新右端点
if(a[i][j]){
topr[j]=m;
nowr=j;
}else{
topr[j] = min(topr[j], nowr-1);
// 更新答案
lin = min(up[j], topr[j]-topl[j]+1);
ans1 = max(ans1, lin*lin);
ans2 = max(ans2, up[j]*(topr[j]-topl[j]+1));
}
}
}
}
int main(){
int i,j;
scanf("%d%d",&n,&m);
for(i=1; i<=n; ++i){
for(j=1; j<=m; ++j){
scanf("%d",&a[i][j]);
}
}
// 改变棋盘,把行数+列数为奇数或偶数的位置异或 多谢 dcx%dl 提醒
for(i=1; i<=n; ++i){
for(j=1; j<=m; ++j){
if((i+j)&1) a[i][j]^=1;
}
}
// 求一下全 1 子矩阵,求一下全 0 子矩阵
getans();
for(i=1; i<=n; ++i){
for(j=1; j<=m; ++j){
a[i][j] = !a[i][j];
}
}
getans();
printf("%d\n%d\n",ans1,ans2);
return 0;
}
还是长度好用啊,位置对坐标有要求,我看不懂还是算了
以后就用长度吧
#include<iostream>
using namespace std;
const int N=2001;
int h[N][N],l[N][N],r[N][N],a[N][N];
int n,m;
int ans1,ans2;
void init(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]&a[i][j-1])l[i][j]=l[i][j-1]+1;//左边不能再拓展了长度为0,但是它的右边那一块可向左拓展长度为1
if(a[i][m-j+1]&a[i][m-j+2])r[i][m-j+1]=r[i][m-j+2]+1;
if(a[i][j]&a[i-1][j])h[i][j]=h[i-1][j]+1;
}
}
}
int main(){
int cntF=0;
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char c;
cin>>c;
if(c=='F')a[i][j]=1,cntF++;
}
}
init();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(h[i][j]){
l[i][j]=min(l[i][j],l[i-1][j]);
r[i][j]=min(r[i][j],r[i-1][j]);
//如果下比上长,较短的上面那条边会约束你可拓展的长度
//如果上比下长,较短的下面那条边会约束你可拓展的长度
}
//int temp=min(h[i][j]+1 , l[i][j]+r[i][j]+1);
//ans1=max(ans1,temp*temp);
ans2=max(ans2,(h[i][j]+1)*(l[i][j]+r[i][j]+1));
}
}
if(cntF==0)cout<<0;
else cout<<ans2*3;
}