[ZJOI2007]棋盘制作
做题日期:2020.12.01
\(【题目描述】\)
有一个\(N\cdot M(N,M \leq 10^3)\)的\(01\)棋盘,问棋盘上最大的01交错(即相邻两个数不相同)的正方形和矩形的大小分别是多少。
\(【输入样例】\)
3 3
1 0 1
0 1 0
1 0 0
\(【输出样例】\)
4
6
\(【考点】\)
动态规划、悬线法
\(【做法】\)
悬线法模板。定义\(left[i][j]\)表示\((i,j)\)到最左能到达的点的纵坐标,\(right[i][j]\)表示\((i,j)\)到最右能到达的点的纵坐标,\(up[i][j]\)表示\((i,j)\)到最上能到达的点与\((i,j)\)之间的距离。
因为矩阵要求数字互不相同,因此在\(a[i][j]!=a[i-1][j]\)或\(a[i][j]!=a[i][j-1]\)或\(a[i][j]!=a[i][j+1]\)时转移即可。
处理正方形,只需要在答案\(ans=\max(ans,(right[i][j]-left[i][j]+1)\cdot up[i][j])\)转移的时候,获取当前最大矩阵的两条边中较小的那一条边,即为当前最大正方形的变成,使用其平方转移即可。
\(【代码】\)
#include<cstdio>
#include<iomanip>
using namespace std;
const int N=2e3+50;
int a[N][N];
int lft[N][N],rgt[N][N],up[N][N];
int n,m,ans1,ans2;
inline int Min(int a,int b){return a<b?a:b;}
inline int Max(int a,int b){return a>b?a:b;}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
lft[i][j]=rgt[i][j]=j;//初始化
up[i][j]=1;
}
}
for(int i=1;i<=n;i++){
for(int j=2;j<=m;j++){
if(a[i][j]!=a[i][j-1]) lft[i][j]=lft[i][j-1];//左右转移
}
}
for(int i=1;i<=n;i++){
for(int j=m-1;j>=1;j--){
if(a[i][j]!=a[i][j+1]) rgt[i][j]=rgt[i][j+1];//左右转移
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(i>1&&a[i][j]!=a[i-1][j]){
rgt[i][j]=Min(rgt[i-1][j],rgt[i][j]);
lft[i][j]=Max(lft[i-1][j],lft[i][j]);//上下转移
up[i][j]=up[i-1][j]+1;
}
int mine=Min(up[i][j],rgt[i][j]-lft[i][j]+1);
ans1=Max(ans1,mine*mine);
ans2=Max(ans2,(rgt[i][j]-lft[i][j]+1)*up[i][j]);
}
}
printf("%d\n%d\n",ans1,ans2);
return 0;
}

浙公网安备 33010602011771号