Luogu 1169 [ZJOI2007]棋盘制作 - 动态规划+单调栈

Description

给一个01矩阵, 求出最大的01交错的正方形和最大的01交错的矩阵

Solution

用动态规划求出最大的正方形, 用单调栈求出最大的矩阵。

在这里仅介绍求出最大正方形(求最大矩阵 = 单调栈裸题  传送门 : 不会单调栈的同学可以去学

 

定义数组$f[ i ][ j ]$ 为以$(i, j) $为右下角的正方形的边长

$up[ i ][ j ]$ 表示从点$(i, j)$往上 $01$交错的长度

$lef[ i ][ j ]$ 表示从点$(i, j)$往右$01$交错的长度

当 $a[ i ][ j ] != a[i - 1][j - 1]$时才可由上一个正方形继续拓展, 否则长度 $f[ i ][ j ] = 1$

于是有转移方程:

$f[ i ][ j ] = 1$   $a[ i ][ j ] == a[i - 1][j - 1]$

$f[ i ][ j ] = min(f[ i - 1][ j - 1] + 1, lef[ i ][ j ],  up[ i ][ j ])$     $ a[ i ][ j ] != a[i - 1][ j ]$

 

Code

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rd read()
 5 #define rep(i,a,b) for(register int i = (a); i <= (b); i++)
 6 #define per(i,a,b) for(register int i = (a); i >= (b); --i)
 7 #define R register
 8 using namespace std;
 9 
10 const int N = 3e3;
11 
12 int n, m, a[N][N], pre[N], nxt[N], h[N], ans2;
13 int lf[N][N], u[N][N], f[N][N], ans1;
14 int st[N], tp;
15 
16 int read() {
17     int X = 0, p = 1; char c = getchar();
18     for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1;
19     for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 +  c - '0';
20     return X * p;
21 }
22 
23 void work(int x) {
24     rep(i, 1, m) pre[i] = 0, nxt[i] = m + 1;
25     rep(i, 1, m)
26         if(a[x][i] != a[x - 1][i]) h[i]++;
27         else h[i] = 1;
28     tp = 0;
29     rep(i, 1, m) {
30         int pr = 0;
31         while(tp) {
32             if(h[st[tp]] >= h[i]) tp--;
33             else {
34                 pr = st[tp]; break;
35             }
36         }
37         pre[i] = pr;
38         st[++tp] = i;
39     }
40     tp = 0;
41     per(i, m, 1) {
42         int nt = m + 1;
43         while(tp) {
44             if(h[st[tp]] >= h[i]) tp--;
45             else {
46                 nt = st[tp]; break;
47             }
48         }
49         nxt[i] = nt;
50         st[++tp] = i;
51     }
52     rep(i, 1, m) {
53         int nt = nxt[i], pr = pre[i];
54         rep(j, i + 1, nt)
55             if(a[x][j] == a[x][j - 1]) {nt = j; break;}
56         per(j, i - 1, pr)
57             if(a[x][j] == a[x][j + 1]) {pr = j; break;}
58         ans2 = max(ans2, (nt - pr - 1) * h[i]);
59     }
60 }
61 
62 int main()
63 {
64     n = rd; m = rd;
65     memset(a, -1, sizeof(a));
66     rep(i, 1, n) rep(j, 1, m) a[i][j] = rd;
67     rep(i, 1, n) rep(j, 1, m) {
68         f[i][j] = 1;
69         if(a[i][j] != a[i][j - 1]) 
70             lf[i][j] = lf[i][j - 1] + 1;
71         else lf[i][j] = 1;
72         if(a[i][j] != a[i - 1][j]) 
73             u[i][j] = u[i - 1][j] + 1;
74         else u[i][j] = 1;
75         if(a[i][j] != a[i - 1][j - 1]) continue;
76         f[i][j] = min(u[i][j], lf[i][j]);
77         f[i][j] = min(f[i - 1][j - 1] + 1, f[i][j]);
78         ans1 = max(ans1, f[i][j]);
79     }
80     printf("%d\n", ans1 * ans1);
81     rep(i, 1, n) work(i);
82     printf("%d\n", ans2);
83 }
View Code

 

转载于:https://www.cnblogs.com/cychester/p/9577963.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值