动态规划——悬线法

这篇博客介绍了如何使用动态规划的悬线法来解决寻找棋盘和矩阵中最大子矩形的问题。通过维护极大悬线的高度、左扩展边界和右扩展边界,可以有效地找到具有最大面积的连续相同元素的矩形。博客提供了三个实例,分别是P1169棋盘制作、P4147玉蟾宫和P2701求最大正方形,每个例子都展示了如何应用这种方法来计算最大正方形的边长。
摘要由CSDN通过智能技术生成

动态规划——悬线法

悬线法用来求解最大子矩形问题。

  • 极大悬线:以某个点为悬线的下端点,一直往上延伸的最大可行宽度为 1 1 1的线段。
  • 左右扩展:将极大悬线向左向右进行最大化扩展。

因此定义变量 h [ x ] h[x] h[x] l [ x ] l[x] l[x] r [ x ] r[x] r[x],分别表示极大悬线的高度,左扩展的边界,右扩展的边界。

例题

P1169 棋盘制作

#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;
}

P4147 玉蟾宫

#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;
}

P2701 求最大正方形

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[r1][c1],dp[r][c1],dp[r1][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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值