C++ 算法学习——1.8 悬线法

1.问题引入:对于一个矩形图,图中放置着不少障碍,要求出最大的不含障碍的矩形。

2.分析:显然一个极大矩形是左右上下都被障碍挡住,无法再扩大的矩形,此时障碍也包括边界。

3.方法:悬线法考虑以当前点所在行为下界,以往上能达到的最大距离为高度,正上方所有点的往左最大距离的最小值和往右最大距离的最小值 之和作为宽的矩形。

其核心代码固定,使用时可以考虑直接套用。如下:

1.初始化求每个点leftmax,rightmax代码,0表示有障碍,不可走:

cpp 复制代码
void initialize(int** G, int** leftmax, int** rightmax, int n, int m) {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (!G[i][j]) continue;
            leftmax[i][j] = leftmax[i][j - 1] + 1;
        }
    }

    for (int i = 1; i <= n; i++) {
        for (int j = m; j >= 1; j--) {
            if (!G[i][j]) continue;
            rightmax[i][j] = rightmax[i][j + 1] + 1;
        }
    }
}

2.求最大矩形面积的代码:

cpp 复制代码
for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            if(i > 1 && G[i][j] && G[i-1][j]){
                upmax[i][j] = upmax[i-1][j] + 1;
                leftmax[i][j] = min(leftmax[i][j], leftmax[i-1][j]);//这样操作可以确保顺序遍历时,每个元素的leftmax都变为正上方元素的最小leftmax
                rightmax[i][j] = min(rightmax[i][j], rightmax[i-1][j]);//同理
            }
            ans = max(ans, (upmax[i][j] + 1) * (leftmax[i][j] + rightmax[i][j] - 1)); //高度+1(加上自身),宽度-1(因为往左包含了当前点,往右也包含了当前点,当前点算了两次)
        }
    }

P1. 洛谷p4147玉蟾宫

cpp 复制代码
#include<iostream>
#include<cmath>
using namespace std;
int n,m;

void initialize(int** G, int** leftmax, int** rightmax, int n, int m) {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (!G[i][j]) continue;
            leftmax[i][j] = leftmax[i][j - 1] + 1;
        }
    }

    for (int i = 1; i <= n; i++) {
        for (int j = m; j >= 1; j--) {
            if (!G[i][j]) continue;
            rightmax[i][j] = rightmax[i][j + 1] + 1;
        }
    }
}

void showcurmap(int** a)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        cout<<a[i][j]<<" ";
        cout<<endl;
    }
}

int main()
{
    cin>>n>>m;//考虑图置中,有效避免越界
    int** G;int**leftmax;int**rightmax;int** upmax;
    G=new int*[n+2];
    leftmax=new int*[n+2];
    rightmax=new int*[n+2];
    upmax=new int*[n+2];
    for(int i=0;i<=n+1;i++)
    {
        G[i]=new int[m+2]{0};
        leftmax[i]=new int[m+2]{0};
        rightmax[i]=new int[m+2]{0};
        upmax[i]=new int[m+2]{0};
    }

    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        char put;cin>>put;
        if(put=='F') G[i][j]=1;
    }
    initialize(G,leftmax,rightmax,n,m);
    long long ans=0;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            if(i > 1 && G[i][j] && G[i-1][j]){
                upmax[i][j] = upmax[i-1][j] + 1;
                leftmax[i][j] = min(leftmax[i][j], leftmax[i-1][j]);//这样操作可以确保顺序遍历时,每个元素的leftmax都变为正上方元素的最小leftmax
                rightmax[i][j] = min(rightmax[i][j], rightmax[i-1][j]);//同理
            }
            ans = fmax(ans, (upmax[i][j] + 1) * (leftmax[i][j] + rightmax[i][j] - 1)); //高度+1(加上自身),宽度-1(因为往左包含了当前点,往右也包含了当前点,当前点算了两次)
        }
    }
    cout<<3*ans;
    //showcurmap(G);
}
相关推荐
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码4 天前
嵌入式学习路线
学习
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。4 天前
2026.2.25监控学习
学习
im_AMBER4 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J4 天前
从“Hello World“ 开始 C++
c语言·c++·学习