zoukankan      html  css  js  c++  java
  • 数据结构 03栈

    栈模拟:

    单调栈:

    下面四个题是连续的,单调栈->直方图中最大的矩形->城市游戏->最大面积

    单调栈

    描述:

    给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。
    
    输入格式
    第一行包含整数 N,表示数列长度。
    
    第二行包含 N 个整数,表示整数数列。
    
    输出格式
    共一行,包含 N 个整数,其中第 i 个数表示第 i 个数的左边第一个比它小的数,如果不存在则输出 −1。
    
    数据范围
    1≤N≤105
    1≤数列中元素≤109
    输入样例:
    5
    3 4 2 7 5
    输出样例:
    -1 3 -1 2 2
    

    代码:

    //模拟栈,始终保证当前序列的单调递增
    #include <iostream>
    
    using namespace std;
    
    const int N = 100010;
    
    int n;
    int stk[N], tot;
    
    int main()
    {
        cin >> n;
        for (int i = 1; i <= n; i ++ )
        {
            int x; scanf("%d", &x);
            
            while (tot >= 1 && stk[tot] >= x) tot --;
            
            if (tot >= 1) cout << stk[tot] << " ";
            else cout << "-1" << " ";
            
            stk[++ tot] = x;
        }
        
        return 0;
    }
    

    直方图中最大的矩形

    题目:

    直方图是由在公共基线处对齐的一系列矩形组成的多边形。

    矩形具有相等的宽度,但可以具有不同的高度。

    例如,图例左侧显示了由高度为 2,1,4,5,1,3,32,1,4,5,1,3,3 的矩形组成的直方图,矩形的宽度都为 11:

    2559_1.jpg

    通常,直方图用于表示离散分布,例如,文本中字符的频率。

    现在,请你计算在公共基线处对齐的直方图中最大矩形的面积。

    图例右图显示了所描绘直方图的最大对齐矩形。

    输入格式

    输入包含几个测试用例。

    每个测试用例占据一行,用以描述一个直方图,并以整数 nn 开始,表示组成直方图的矩形数目。

    然后跟随 nn 个整数 h1hnh1,…,hn。

    这些数字以从左到右的顺序表示直方图的各个矩形的高度。

    每个矩形的宽度为 11。

    同行数字用空格隔开。

    当输入用例为 n=0n=0 时,结束输入,且该用例不用考虑。

    输出格式

    对于每一个测试用例,输出一个整数,代表指定直方图中最大矩形的区域面积。

    每个数据占一行。

    请注意,此矩形必须在公共基线处对齐。

    数据范围

    1n1000001≤n≤100000,
    0hi10000000000≤hi≤1000000000

    输入样例:

    7 2 1 4 5 1 3 3
    4 1000 1000 1000 1000
    0
    

    输出样例:

    8
    4000

    代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long LL;
    
    const int N = 100010;
    
    int n;
    int h[N];
    int l[N], r[N];//分别记录左边第一个比当前高度低的下标,和当前第一个比当前高度高的下标
    int q[N], tot;//单调队列【单调栈】,记录单调栈的下标
    int main()
    {
        while (cin >> n, n)
        {
            for (int i = 1; i <= n; i ++ ) scanf("%d", &h[i]);
            h[0] = h[n + 1] = -1;
            //正着求一边单调上升栈,记录l,左边第一个比他小的高度
            tot = 0;
            q[0] = 0;
            for (int i = 1; i <= n; i ++ )
            {
                while (tot >= 1 && h[i] <= h[q[tot]]) tot --;
                l[i] = q[tot];
                q[++ tot] = i;
            }
            //泛着求一边单调上升栈,记录r,右边第一个比他小的高度
            tot = 0;
            q[0] = n + 1;
            for (int i = n; i >= 1; i -- )
            {
                while (tot >= 1 && h[i] <= h[q[tot]]) tot --;
                r[i] = q[tot];
                q[++ tot] = i;
            }
            
            LL ans = 0;
            for (int i = 1; i <= n; i ++ ) 
                ans = max(ans, (LL)h[i] * (r[i] - l[i] - 1));
                
            cout << ans << "
    ";
        }
        return 0;
    }
    

    城市游戏

    题目:

    给定一个 N×M 的 01 矩阵,矩阵下标从 0 开始。
    
    有 Q 个询问,第 i 个询问为:将矩阵中 (xi,yi) 的元素改成 0 之后,只包含 1 的子矩阵的最大面积是多少。
    
    注意:
    
    每次询问均是独立的。
    询问方格内元素可能本来就是 0。
    子矩阵的面积是指矩阵的大小。
    输入格式
    第一行包含两个整数 N,M。
    
    接下来 N 行,每行包含 M 个 01 字符。
    
    再一行包含整数 Q。
    
    接下来 Q 行,每行包含 2 个整数 (xi,yi)。
    
    输出格式
    每个询问输出一行一个结果,表示最大面积。
    
    数据范围
    对于 20% 的数据,1≤N,M,Q≤10
    对于 50% 的数据,1≤N,M,Q≤100
    对于 100% 的数据,1≤N,M≤2000,1≤Q≤105, 0≤xi<n,0≤yi<m
    输入样例:
    4 2
    10
    11
    11
    11
    3
    0 0
    2 0
    3 1
    输出样例:
    6
    3
    4
    

    代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 1010;
    
    int n, m;
    int g[N][N];
    int s[N][N];
    int up[N][N], down[N][N];
    
    void print(int a[N][N])
    {
        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;
        for (int i = 1; i <= n; i ++ ) {
            for (int j = 1; j <= m; j ++ )
            {
                char c[2]; scanf("%s", c);
                if (*c == 'F') g[i][j] = 1;
                else g[i][j] = 0;
            }
        }
        
        // print(g);
        for (int i = 1; i <= n; i ++ )
        {
            int sum = 0;
            for (int j = m; j >= 1; j -- )
            {
                if (g[i][j] == 1) sum ++;
                else sum = 0;
                s[i][j] = sum;
            }
        }
        // print(s);
        
        for (int j = 1; j <= m; j ++ )
        {
            get(up);
            get(down)
        }
        
        return 0;  
    }
    

    最大面积

    题目:

    给定一个 N×M 的 01 矩阵,矩阵下标从 0 开始。
    
    有 Q 个询问,第 i 个询问为:将矩阵中 (xi,yi) 的元素改成 0 之后,只包含 1 的子矩阵的最大面积是多少。
    
    注意:
    
    每次询问均是独立的。
    询问方格内元素可能本来就是 0。
    子矩阵的面积是指矩阵的大小。
    输入格式
    第一行包含两个整数 N,M。
    
    接下来 N 行,每行包含 M 个 01 字符。
    
    再一行包含整数 Q。
    
    接下来 Q 行,每行包含 2 个整数 (xi,yi)。
    
    输出格式
    每个询问输出一行一个结果,表示最大面积。
    
    数据范围
    对于 20% 的数据,1≤N,M,Q≤10
    对于 50% 的数据,1≤N,M,Q≤100
    对于 100% 的数据,1≤N,M≤2000,1≤Q≤105, 0≤xi<n,0≤yi<m
    输入样例:
    4 2
    10
    11
    11
    11
    3
    0 0
    2 0
    3 1
    输出样例:
    6
    3
    4
    

    代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 2010;
    
    int n, m, Q;
    char g[N][N];
    int s[N][N];
    int l[N], r[N], q[N];
    int U[N], D[N], L[N], R[N];
    
    int calc(int *h, int n)
    {
        h[0] = h[n + 1] = -1;
        
        int tot = 0;
        q[0] = 0;
        for (int i = 1; i <= n; i ++ ) 
        {
            while (h[i] <= h[q[tot]]) tot --;
            l[i] = q[tot];
            q[++ tot] = i;
        }
        
        tot = 0;
        q[0] = n + 1;
        for (int i = n; i >= 1; i -- )
        {
            while (h[i] <= h[q[tot]]) tot --;
            r[i] = q[tot];
            q[++ tot] = i;
        }
        
        int ans = 0;
        for (int i = 1; i <= n; i ++ ) 
            ans = max(ans, h[i] * (r[i] - l[i] - 1));
        return ans;
    }
    void init()
    {
        //上
        memset(s, 0, sizeof s);
        for (int i = 1; i <= n; i ++ ) 
        {
            for (int j = 1; j <= m; j ++ ) 
                if (g[i][j] == '1') s[i][j] = s[i - 1][j] + 1;
                else s[i][j] = 0;
            U[i] = max(U[i - 1], calc(s[i], m));
        }
        //下
        memset(s, 0, sizeof s);    
        for (int i = n; i >= 1; i -- )
        {
            for (int j = 1; j <= m; j ++ ) 
                if (g[i][j] == '1') s[i][j] = s[i + 1][j] + 1;
                else s[i][j] = 0;
            D[i] = max(D[i + 1], calc(s[i], m));
        }
        //左
        memset(s, 0, sizeof s);
        for (int j = 1; j <= m; j ++ )
        {
            for (int i = 1; i <= n; i ++ ) 
                if (g[i][j] == '1') s[j][i] = s[j - 1][i] + 1;
                else s[j][i] = 0;
            L[j] = max(L[j - 1], calc(s[j], n));
        }
        //右
        memset(s, 0, sizeof s);
        for (int j = m; j >= 1; j -- )
        {
            for (int i = 1; i <= n; i ++ ) 
                if (g[i][j] == '1') s[j][i] = s[j + 1][i] + 1;
                else s[j][i] = 0;
            R[j] = max(R[j + 1], calc(s[j], n));
        }
    }
    int main()
    {
        cin >> n >> m; 
        for (int i = 1; i <= n; i ++ ) scanf("%s", g[i] + 1);
        
        init();
        
        cin >> Q;
        while (Q -- )
        {
            int x, y; scanf("%d%d", &x, &y);
            x ++, y ++;
            printf("%d
    ", max(max(U[x - 1], D[x + 1]), max(L[y - 1], R[y + 1])));
        }
    }
    

      

  • 相关阅读:
    计算机系统概述
    Qt学习--初学注意事项
    Qt实现一个简单的TextEditor
    Qt 用户登录界面
    C++ 模板
    多态与虚函数
    继承与派生
    C++ 运算符重载
    web安全-点击劫持
    web安全问题-cookie
  • 原文地址:https://www.cnblogs.com/Iamcookieandyou/p/14828469.html
Copyright © 2011-2022 走看看