最近学习悬线法,所以就找了这道题练练手。
因为棋盘是01交错的,所以我们可以先处理一下棋盘,从而转化为求最大子矩形问题。
第一问可以用DP也可以用悬线法,我DP写得比较熟所以用了DP。
第二问直接用悬线法求出处理过的棋盘的最大子矩形即可
代码:
#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; }