动态规划——悬线法
悬线法用来求解最大子矩形问题。
- 极大悬线:以某个点为悬线的下端点,一直往上延伸的最大可行宽度为 1 1 1的线段。
- 左右扩展:将极大悬线向左向右进行最大化扩展。
因此定义变量 h [ x ] h[x] h[x], l [ x ] l[x] l[x]和 r [ x ] r[x] r[x],分别表示极大悬线的高度,左扩展的边界,右扩展的边界。
例题
#include <bits/stdc++.h>
#define FR freopen("in.txt", "r", stdin)
using namespace std;
typedef long long ll;
int n, m;
int matrix[2005][2005];
int H[2005];
int L[2005];
int R[2005];
int main()
{
scanf("%d %d", &n, &m);
for (int r = 1; r <= n; r++)
{
for (int c = 1; c <= m; c++)
{
scanf("%d", &matrix[r][c]);
}
}
int ans1 = 0, ans2 = 0;
for (int r = 1; r <= n; r++)
{
for (int c = 1; c <= m; c++)
{
if (matrix[r][c] != matrix[r - 1][c])
H[c]++;
else
H[c] = 1;
}
for (int c = 1; c <= m; c++)
{
L[c] = c;
while (L[c] > 1 && H[c] <= H[L[c] - 1] && matrix[r][L[c]] != matrix[r][L[c] - 1])
L[c] = L[L[c] - 1];
}
for (int c = m; c >= 1; c--)
{
R[c] = c;
while (R[c] < m && H[c] <= H[R[c] + 1] && matrix[r][R[c]] != matrix[r][R[c] + 1])
R[c] = R[R[c] + 1];
}
for (int c = 1; c <= m; c++)
{
ans2 = max(ans2, H[c] * (R[c] - L[c] + 1));
int a = min(H[c], (R[c] - L[c] + 1));
ans1 = max(ans1, a * a);
}
}
printf("%d\n%d\n", ans1, ans2);
return 0;
}
#include <bits/stdc++.h>
#define FR freopen("in.txt", "r", stdin)
using namespace std;
typedef long long ll;
int n, m;
int matrix[2005][2005];
int H[2005];
int L[2005];
int R[2005];
int main()
{
cin >> n >> m;
for (int r = 1; r <= n; r++)
{
for (int c = 1; c <= m; c++)
{
char t;
cin >> t;
matrix[r][c] = t == 'F';
}
}
int ans1 = 0, ans2 = 0;
for (int r = 1; r <= n; r++)
{
for (int c = 1; c <= m; c++)
{
if (matrix[r][c])
H[c]++;
else
H[c] = 0;
}
for (int c = 1; c <= m; c++)
{
L[c] = c;
while (L[c] > 1 && H[c] <= H[L[c] - 1])
L[c] = L[L[c] - 1];
}
for (int c = m; c >= 1; c--)
{
R[c] = c;
while (R[c] < m && H[c] <= H[R[c] + 1])
R[c] = R[R[c] + 1];
}
for (int c = 1; c <= m; c++)
{
ans2 = max(ans2, H[c] * (R[c] - L[c] + 1));
//int a = min(H[c], (R[c] - L[c] + 1));
//ans1 = max(ans1, a * a);
}
}
printf("%d\n", 3 * ans2);
return 0;
}
DP方程为:
d p [ r ] [ c ] = min { d p [ r − 1 ] [ c − 1 ] , d p [ r ] [ c − 1 ] , d p [ r − 1 ] [ c ] } + 1 dp[r][c] = \min\{dp[r - 1][c - 1],dp[r ][c - 1],dp[r - 1][c]\} + 1 dp[r][c]=min{dp[r−1][c−1],dp[r][c−1],dp[r−1][c]}+1
考虑对 ( r , c ) (r,c) (r,c)进行扩展,保证三个方向,向上向右都能扩展的最大边长为紧挨着三个正方形的最小边长。
#include <bits/stdc++.h>
#define FR freopen("in.txt", "r", stdin)
using namespace std;
typedef long long ll;
int n, T;
int matrix[2005][2005];
int dp[2005][2005];
int main()
{
scanf("%d %d", &n, &T);
for (int i = 0; i < T; i++)
{
int r, c;
scanf("%d %d", &r, &c);
matrix[r][c] = 1;
}
int mx = 0;
for (int r = 1; r <= n; r++)
{
for (int c = 1; c <= n; c++)
{
if (matrix[r][c] == 0)
dp[r][c] = min(min(dp[r][c - 1], dp[r - 1][c]), dp[r - 1][c - 1]) + 1;
mx = max(mx, dp[r][c]);
}
}
printf("%d", mx);
return 0;
}