• 「ZJOI2007」棋盘制作


    在一个$N imes M$的$0 1$矩阵中,求面积最大的相邻位置数字不同的矩形和正方形。

    题目链接:BZOJ1057

    乍一看,也许暴力可以解决问题,可以暴力的枚举所取图形的长和宽,然后再暴力的枚举。

    但是这样的时间复杂度高达$O(n^2 m^2)$,肯定行不通,而且很难写。

    这时候,我们引入“悬线法”。

     对于每个位置,我们预处理出此节点向上方最长能够延申的合法长度$left$。

    再用另一个数组预处理出此节点向下方最长能够延申的合法长度$right$。

    然后再横向处理矩阵,求出每个点的横向长度合法最长值,用一条线连结。

    称为「悬线」。求出悬线向上向下能延伸到的最远位置,则悬线上下移动的轨迹为一个合法子矩阵,

    且这个子矩阵的上边、左边、下边不能延伸。如果它的右边可以延伸,则在接下来的枚举中,延伸得到的矩阵可以被枚举到,否则它就是一个极大合法子矩阵。

    时间复杂度$O(nm)$

    代码如下

    #include <stdio.h>
    #include <algorithm>
    int n, m;
    int qrt(int x)
    {
        return x * x;
    }
    int pe[2005][2005], b[2005][2005], c[2005][2005];
    int main()
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                scanf("%d", &pe[i][j]);
            }
        }
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                if (j == 1 || pe[i][j] == pe[i][j - 1])
                    b[i][j] = 1;
                else
                {
                    b[i][j] = b[i][j - 1] + 1;
                }
            }
            for (int j = m; j >= 1; j--)
            {
                if (j == m || pe[i][j] == pe[i][j + 1])
                    c[i][j] = 1;
                else
                {
                    c[i][j] = c[i][j + 1] + 1;
                }
            }
        }
        int sq_max = 0, rec_max = 0;
        for (int j = 1; j <= m; j++)
        {
            int up = 0, left = 0, right = 0;
            for (int i = 1; i <= n; i++)
            {
                if (i == 1 || pe[i][j] == pe[i - 1][j])
                {
                    up = 1;
                    left = b[i][j];
                    right = c[i][j];
                }
                else
                {
                    up++;
                    left = std::min(left, b[i][j]);
                    right = std::min(right, c[i][j]);
                }
                rec_max = std::max(rec_max, up * (left + right - 1));
                sq_max = std::max(sq_max, qrt(std::min(left + right - 1, up)));
            }
        }
        printf("%d
    %d
    ", sq_max, rec_max);
    
        return 0;
    }
    人十我百 人百我万
  • 相关阅读:
    Individual Method Selection Survey rubric
    Xcode 出现Thread 1: signal SIGABRT
    C/C++生成随机数
    《深入浅出深度学习:原理剖析与python实践》第八章前馈神经网络(笔记)
    操作系统--精髓与设计原理(第八版)第三章复习题答案
    操作系统--精髓与设计原理(第八版)第二章复习题答案
    Python知识点整理
    C++ <queue>用法
    C语言结构体用法
    Mac安装Qt出现错误Could not resolve SDK Path for 'macosx'
  • 原文地址:https://www.cnblogs.com/bestcoder-Yurnero/p/11235667.html
Copyright © 2020-2023  润新知