数据结构 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 << "\n";
    }
    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\n", max(max(U[x - 1], D[x + 1]), max(L[y - 1], R[y + 1])));
    }
}

  

 

posted @ 2021-05-30 17:32  rookie161  阅读(80)  评论(0编辑  收藏  举报