悬线法用于求解最大子矩阵问题,资料详见:这篇论文
对于red-and-blue crisscross 方阵可以用dp,既可以用合并两个小方阵得到一个大方阵,合并过程如下图:
我们可以把两个绿色的3*3小方阵合成一个4*4大方阵,只要符合color[i][j]!=color[i-1][j]&&color[i][j]!=color[i][j-1]&&color[i][j]==color[i-k][j-k]( k为min(dp[i-1][j],dp[i][j-1]));
dp[i][j]表示正方形的右下坐标为(i,j)的最大方阵的边长;
#include<stdio.h>
#include<string.h>
#define N 1100
int H[N][N],right[N][N],left[N][N],mat[N][N],n,m;
void init()
{
int i,j,b;
for(i=1;i<=n;i++){
for(j=1,b=0;j<=m;j++){
if(!mat[i][j]) b=0;
else if(!b&&mat[i][j]) b=j;
left[i][j]=b;
}
for(j=m,b=0;j>=1;j--){
if(!mat[i][j]) b=0;
else if(!b&&mat[i][j]) b=j;
right[i][j]=b;
}
}
}
int max(int a,int b){ return a<b?b:a; }
int min(int a,int b){ return a>b?b:a; }
int solve()
{
int i,j,ans=0;
memset(H,0,sizeof(H));
for(i=1;i<=n;i++){
for(j=1;j<=m;j++)
{
if(mat[i][j]){
H[i][j]=H[i-1][j]+1;
if(mat[i-1][j])
{
left[i][j]=max(left[i][j],left[i-1][j]);
right[i][j]=min(right[i][j],right[i-1][j]);
}
ans=max(ans,2*(right[i][j]-left[i][j]+1)+2*H[i][j]);
}
}
}
return ans;
}
char in[N][N];
void input()
{
int i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++) scanf("%s",in[i]+1);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
mat[i][j]=in[i][j]=='R';
}
int dp[N][N];
int intersect()
{
int i,j,k,ans=0;
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
dp[i][j]=1;
if(mat[i-1][j]!=mat[i][j]&&mat[i][j]!=mat[i][j-1]){
k=min(dp[i-1][j],dp[i][j-1]);
if(mat[i][j]==mat[i-k][j-k])k++;
dp[i][j]=max(dp[i][j],k);
ans=max(ans,dp[i][j]*4);
}
}
}
return ans;
}
int main()
{
int ans,i,j,cas,cass;
scanf("%d",&cass);
for(cas=1;cas<=cass;cas++)
{
input();
ans=intersect();
init();
ans=max(ans,solve());
for(i=1;i<=n;i++) for(j=1;j<=m;j++) mat[i][j]=1-mat[i][j];
init();
ans=max(ans,solve());
printf("Case #%d: %d\n",cas,ans);
}
return 0;
}