zoukankan      html  css  js  c++  java
  • 51nod1158 单调栈 个人的想法以及分析

    单调栈,顾名思义就是保持内部元素单调性并且保证FILO的一种数据结构。 单调栈的代码实现没有什么难度,但是使用姿势难以想到。

    在51nod1158中描述了这样一个问题: 给定一个 0-1 矩阵, 求这个矩阵最大的全 1 子矩阵的面积。

    问题十分好理解。 

    现在,我们将这个问题拆分成一些子问题来逐个击破。

    首先,为了保证程序操作的规律性与有序性,我们需要把问题等价成一个任意规模下的问题。 比如我们可以将其等价为:

      对于第 i 行(列), 求出 以它为边界的最大全 1 子矩阵面积。

      这样子我们最终所需要的其实是 max(ansi);

    接下来解决 i 规模下的问题:

      由于矩阵其实是一种二维结构,对二维结构的处理是十分复杂并且耗时的,所以我们考虑把二维的问题转变为一维的问题。

      这样子我们肯定没有办法直接处理。 由于题目要求的是求出子矩阵面积, 所以我们考虑对于一个点 (i,j), 它周围会有多大的全1矩阵。

      首先我们需要在行和列上对 (i,j)  覆盖范围进行扩展。 那么我们自然而然会想到统计的方法。 即统计出行上扩展的长度,以及在此基础上列扩展的长度。

      扩展行的长度比较容易,我们只需要预处理矩阵。 对于 (i,j) 定义 cnt[i][j] 表示它在行上扩展的长度。 则容易得到递推式 cnt[i][j] = (a[i][j] == 1 ? cnt[i][j-1] + 1 : 0)

      列扩展的难点在与需要依赖与行扩展的结果。 每次所扩展的范围一定是扩展到一个离 ( i , j ) 最远的行扩展不为 0 的位置。 这个很好理解,然后用行扩展乘列扩展就是最终答案。

      那我们现在的问题转化为如何求解列扩展。

      对于位置 ( i , j ) 我们已知它的行扩展为 cnt[i][j] 那么我们考虑以位置 ( i, j ) 为起点向 ( i , j-1 ) 的方向扩展。 在这个方向上与位置 ( i , j ) 相连且行扩展大于 cnt[i][j] 的列号都是可扩展列。

      所以我们此时需要找到所有 j 列之前的列扩展大于 cnt[i][j] 的列, 程序上来讲就是实现一个单调减栈, 每次入栈 ( i , j ) 时必定会先弹出大于cnt[i][j] 的元素。

      我们从 ( i, j ) 开始向左扩展, 再向右扩展, 就得到了最终的结果。

      代码如下:

      

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 510;
     4 int a[maxn][maxn];
     5 int tmp[maxn][maxn];
     6 int up[maxn], down[maxn];
     7 int main(){
     8     int m,n;
     9     cin >> m >> n;
    10     for(int i = 1; i <= n; i++){
    11         for(int j = 1; j <= m; j++){
    12             scanf("%d", &a[i][j]);
    13         }
    14     }
    15     for(int i = 1; i <= n; i++){
    16         for(int j = 1; j <= m; j++){
    17             if(a[i][j]) tmp[i][j] = tmp[i][j-1] + 1;
    18         }
    19     }
    20     int ans = 0;
    21     for(int j = 1; j <= m; j++){
    22         for(int i = 1; i <= n; i++){
    23             int cur = i-1;
    24             for(; cur && tmp[i][j] <= tmp[cur][j]; cur = up[cur]);
    25             up[i] = cur;    
    26         }
    27         for(int i = n; i > 0; i--){
    28             int cur = i + 1;
    29             for(; cur <= n && tmp[i][j] <= tmp[cur][j]; cur = down[cur]);
    30             down[i] = cur;     
    31         }
    32         for(int i = 1; i <= n; i++){
    33             ans = max(ans, (down[i] - up[i] - 1) * tmp[i][j]);
    34         }
    35     }    
    36     cout << ans << endl;
    37     return 0;
    38 }    
  • 相关阅读:
    深入理解SQL的四种连接-左外连接、右外连接、内连接、全连接
    sql之group by的用法
    jmeter参数化
    jmeter--FTP测试
    jmeter基础概念
    开源性能测试工具——jemeter介绍+安装说明
    mysql安装图解 mysql图文安装教程(详细说明)
    Elasticsearch全文检索优化研究
    如何正确的关闭Elasticsearch集群
    自定义查询系统架构设计分析
  • 原文地址:https://www.cnblogs.com/zzhzz/p/6752689.html
Copyright © 2011-2022 走看看