题解 P1169 【[ZJOI2007]棋盘制作】
chill
2018-02-23 21:27:55
这道题目其实就是P2701巨大的牛棚与P4147玉蟾宫的合并。
P2701求的是可以覆盖的最大正方形,
而P4171求的则是可以覆盖的最大矩形。
首先考虑把黑白相间的棋盘转换成同一个颜色,方便之后的操作。可以通过行标与列标之和的奇偶判断是否应该染上相反的颜色。需要注意的是染完色后应该再将整个矩形都染上相反的颜色,重新进行后面的操作。
### 求最大正方形:
_f[i][j]_ 表示右下角坐标为 _(i,j)_ 的正方形的最大边长。不难发现 _f[i][j]_ 与它周围的 _f[i-1][j-1],f[i-1][j],f[i][j-1]_ 有关系。于是得出
#### f[i][j]=max{f[i-1][j-1],f[i-1][j],f[i][j-1]}+1
### 求最大矩形:(借鉴了P4147题解中XG_Zepto的思路)
建立 _l[i][j],r[i][j]_ 储存坐标 _(i,j)_ 左右最近的障碍位置
建立 _L[i][j],R[i][j]_ 储存坐标 _(i,j)_ 在矩形内左右最远可以取到的位置
建立 _H[i][j]_ 储存坐标 _(i,j)_ 所在矩形的高度
坐标 _(i,j)_ 所在矩形面积为 _h[i][j]*(R[i][j]-L[i][j]-1)
_
### 附上代码:
```cpp
#include <bits/stdc++.h>
using namespace std;
int n,m,tmp,ans1,ans2;
int f[1001][1001],a[1001][1001],l[1001][1001],r[1001][1001],L[1001][1001],R[1001][1001],h[1001][1001];
char ch;
void work()
{
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
f[i][j]=l[i][j]=r[i][j]=L[i][j]=R[i][j]=h[i][j]=0;//初始化
for (int i=1;i<=n;i++)
{
tmp=0;
for (int j=1;j<=m;j++)//计算左边最近障碍位置
if (a[i][j]) l[i][j]=tmp;
else tmp=j,L[i][j]=0;
tmp=m+1;
for (int j=m;j>=1;j--)//计算右边最近障碍位置
if (a[i][j]) r[i][j]=tmp;
else tmp=j,R[i][j]=m+1;
}
for (int i=1;i<=m;i++) R[0][i]=m+1;//细节需留意
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (a[i][j])
{
f[i][j]=min(f[i-1][j-1],min(f[i-1][j],f[i][j-1]))+1;//计算当前正方形边长
h[i][j]=h[i-1][j]+1;//当前矩形高度+1
L[i][j]=max(L[i-1][j],l[i][j]);//计算当前矩形最左遇到的障碍
R[i][j]=min(R[i-1][j],r[i][j]);//计算当前矩形最右遇到的障碍
ans1=max(ans1,f[i][j]*f[i][j]);//求正方形面积最大值
ans2=max(ans2,h[i][j]*(R[i][j]-L[i][j]-1));//求矩形面积最大值
}
}
int main()
{
cin>>n>>m;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
cin>>a[i][j];
if ((i+j)%2!=1) a[i][j]=1-a[i][j];//在相应位置染上相反色
}
work();
for (int i=1;i<=n;i++)//重新染色
for (int j=1;j<=m;j++)
a[i][j]=1-a[i][j];
work();
cout<<ans1<<endl<<ans2<<endl;
return 0;
}
```