2017.9.28今天模拟赛T1就是求最大子矩阵的经典题
然而我已经好久没有写悬线了,以前悬线也是拉的,于是现在就系统的学习一波吧
给定一个N * M的01矩阵,求最大全0矩阵的大小
N^3的做法其实有很多种,前缀和乱搞什么的都可以
考虑N^2的做法
对于任意一个非1的点i,j,记其向上能到达的最长长度为up[i][j]
显然up[i][j] = up[i-1][j] + 1 (a[i][j] == 0)
up[i][j] = 0 (a[i][j] = 1)我们称up[i][j]为一条悬线
显然必然存在一段区间L,R满足 L<=j<=R使得1-i行中 L,R之间所有悬线都>= up[i][j]
令L[i][j]表示ij所能到达的最左端的L,R[i][j]表示i,j所能到达最右端的R
若a[i-1][j] == 0 那么L 和 R就能从i-1,j转移
能到达的最左端必然存在一个障碍或者边界挡住,右端同理
如果L,R要从上一层转移,那么新的L,R就是原先值和这一层左右离i,j最近的障碍的较劣值
显然这个可以再扫描处理为1的点时就求出来
那么对于一个点,以这个点及其悬线为中心的矩阵面积就是(R[i][j] - L[i][j] + 1) * UP[i][j]
悬线法实际上用了极大子矩阵的思想,个人能力有限,也就只能先学到这里了
下面放代码
for(int i = 1; i <= m; i++) l[i] = 1, r[i] = m; for(int i = 1; i <= n; i++){ int pre = 0, nxt = m + 1; for(int j = 1; j <= m; j++) if(a[i][j] == ‘1‘) pre = j, l[j] = 1; else l[j] = Max(l[j], pre + 1); for(int j = m; j >= 1; j--) if(a[i][j] == ‘1‘) nxt = j, r[j] = m; else r[j] = Min(r[j], nxt - 1); for(int j = 1; j <= m; j++) ans = Max(ans, (r[j] - l[j] + 1) * up[i][j]); }
时间: 2024-10-25 04:13:10