• luogu1169 棋盘制作


    题目大意

      有一个有m*n个格子的矩形,每个格子都有黑或白两种颜色。现要求将该矩形分别裁剪成一个小矩形或一个小正方形,使得这个矩形和正方形是个国际象棋棋盘,且面积最大。

    题解

      首先,为了简化问题,我们每隔一个格子将颜色翻转,这样题目就变成了最大01子矩阵问题。解决这类问题需要用到悬线法。

      首先,我们规定一个半极大子矩阵为上、左、右边缘由于有障碍而不可继续向上、左、右方向延伸的矩阵。显然我们要求的矩阵是一个半极大子矩阵。对于一个这样的矩阵,我们定义悬线为上边缘的上一排的一个障碍点所在竖直线在矩阵内的部分。那么一个矩阵就相当于悬线在没有障碍的范围内左右移动的结果。因为矩阵中的每一个点都只对应唯一一个悬线,所以我们可以用通过枚举矩形中的每一个点的方法来枚举到所有的半极大子矩阵。首先悬线的长度可以递推求解。定义一个点对应悬线在半极大子矩形中向右移动的长度为RecR[row][col],向左移动的长度为RecL[row][col]。要知道这两个量,我们还需要知道该点可向左最远延伸的距离L[row][col]和向右最远延伸的距离R[row][col],对于一个点,其RecL[row][col] = min(row1,col1与row,col在同一悬线内,包括row, col){L[row1][col1]}。这样子矩阵的面积就可求了。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    #define Clear(a, val) memset(a, val, sizeof(a))
    const int MAX_ROW = 2010, MAX_COL = 2010, INF = 0x3f3f3f3f;
    int A[MAX_ROW][MAX_COL];
    int HorL[MAX_ROW][MAX_COL], HorR[MAX_ROW][MAX_COL], H[MAX_ROW][MAX_COL], RecL[MAX_ROW][MAX_COL], RecR[MAX_ROW][MAX_COL];//Hor:Horizontal Rec:Rectangle
    int TotRow, TotCol, AnsSq, AnsRec;
    
    void ChangeMap()//一黑一白改为连续黑连续白
    {
        int st = 1;
        for (int row = 1; row <= TotRow; row++)
        {
            for (int col = st; col <= TotCol; col += 2)
                A[row][col] = !A[row][col];
            st = st == 1 ? 2 : 1;
        }
    }
    
    void Solve()
    {
        Clear(HorL, 0), Clear(HorR, 0), Clear(H, 0), Clear(RecL, INF), Clear(RecR, INF);
        for (int row = 1; row <= TotRow; row++)
        {
            for (int col = 1; col <= TotCol; col++)
            {
                if(A[row][col])
                {
                    HorL[row][col] = HorL[row][col - 1] + 1;
                    H[row][col] = H[row - 1][col] + 1; 
                }
            }
            for (int col = TotCol; col >= 1; col--)
                HorR[row][col] = A[row][col] ? HorR[row][col + 1] + 1 : 0;
        }
        
        for (int row = 1; row <= TotRow; row++)
        {
            for (int col = 1; col <= TotCol; col++)
            {
                if (A[row][col])
                {
                    RecL[row][col] = min(HorL[row][col], RecL[row - 1][col]);
                    RecR[row][col] = min(HorR[row][col], RecR[row - 1][col]);
                }
                else
                    RecL[row][col] = RecR[row][col] = INF;
                int curSqEdge = min(H[row][col], RecL[row][col] + RecR[row][col] - 1);
                AnsSq = max(AnsSq, curSqEdge * curSqEdge);
                AnsRec = max(AnsRec, H[row][col] * (RecR[row][col] + RecL[row][col] - 1));
            }
        }
    }
    
    void ReverseMap()
    {
        for (int row = 1; row <= TotRow; row++)
            for (int col = 1; col <= TotCol; col++)
                A[row][col] = !A[row][col];
    }
    
    int main()
    {
        scanf("%d%d", &TotRow, &TotCol);
        for (int row = 1; row <= TotRow; row++)
            for (int col = 1; col <= TotCol; col++)
                scanf("%d", &A[row][col]);
        ChangeMap();
        Solve();
        ReverseMap();
        Solve();
        printf("%d
    %d
    ", AnsSq, AnsRec);
        return 0;
    }
    

      

  • 相关阅读:
    RabbitMQ知识点整理2-相关概念介绍
    RabbitMQ知识点整理1-生产和消费消息
    Java自学-图形界面 Swing中的线程
    Java自学-图形界面 日期控件
    Java自学-图形界面 表格
    Java自学-图形界面 工具栏
    WebStorm 2020.2.3 破解(Mac,windows,Linux)
    消息队列的使用场景
    有关建立虚拟环境的总结
    性能测试-Locust分布式执行
  • 原文地址:https://www.cnblogs.com/headboy2002/p/9427225.html
Copyright © 2020-2023  润新知