最近学习悬线法,所以就找了这道题练练手。
因为棋盘是01交错的,所以我们可以先处理一下棋盘,从而转化为求最大子矩形问题。
第一问可以用DP也可以用悬线法,我DP写得比较熟所以用了DP。
第二问直接用悬线法求出处理过的棋盘的最大子矩形即可
http://wenku.baidu.com/link?url=Z66PIdqkZRuictNUkOktEs4z3kQZJaUqQoJ-4mOLCHVUvV1E_AJSCTXIDyhv6H_H-TWUz1Msbm-1a8qXWm2dk60N8mgMrpIhZC-OE7YZ05m
http://wenku.baidu.com/view/728cd5126edb6f1aff001fbb.html
代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 2000 + 10;
int n,m;
int chess[maxn][maxn],f[maxn][maxn];
int up[maxn][maxn],left[maxn][maxn],right[maxn][maxn];
void init()
{
freopen("chess.in","r",stdin);
freopen("chess.out","w",stdout);
}
void readdata()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
scanf("%d",&chess[i][j]);
if((i + j) & 1)chess[i][j] ^= 1;
}
}
}
int min(int a,int b)
{
return a < b ? a : b;
}
int max(int a,int b)
{
return a > b ? a : b;
}
int dp(int p)
{
int ret = 0;
memset(f,0,sizeof(f));
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
if(chess[i][j] == p)
{
f[i][j] = 1;
f[i][j] = min(f[i-1][j-1],min(f[i-1][j],f[i][j-1])) + 1;
ret = max(ret,f[i][j]);
}
}
}
return ret * ret;
}
int calc(int p)
{
memset(left,0,sizeof(left));
memset(up,0,sizeof(up));
memset(right,0,sizeof(right));
int ret = 0;
for(int i = 1;i <= n;i++)
{
int lo = 0,ro = m + 1;
for(int j = 1;j <= m;j++)
{
if(chess[i][j] == p)
{
up[i][j] = left[i][j] = 0;
lo = j;
}
else
{
up[i][j] = i == 1 ? 1 : up[i-1][j] + 1;
left[i][j] = i == 1 ? lo + 1 : max(left[i-1][j],lo + 1);
}
}
for(int j = m;j >= 1;j--)
{
if(chess[i][j] == p)
{
right[i][j] = m + 1;
ro = j;
}
else
{
right[i][j] = i == 1 ? ro - 1 : min(right[i-1][j],ro - 1);
ret = max(ret,up[i][j] * (right[i][j] - left[i][j] + 1));
}
}
}
return ret;
}
void solve()
{
int ans1 = max(dp(0),dp(1));
int ans2 = max(calc(0),calc(1));
printf("%d\n%d",ans1,ans2);
}
int main()
{
init();
readdata();
solve();
return 0;
}