zoukankan      html  css  js  c++  java
  • [洛谷P1169] [ZJOI2007]棋盘制作

    洛谷题目链接:[ZJOI2007]棋盘制作

    题目描述

    国际象棋是世界上最古老的博弈游戏之一,和中国的围棋、象棋以及日本的将棋同享盛名。据说国际象棋起源于易经的思想,棋盘是一个(8 imes 8)大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳。

    而我们的主人公小Q,正是国际象棋的狂热爱好者。作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W决定将棋盘扩大以适应他们的新规则。

    小Q找到了一张由(N imes M)个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一。小Q想在这种纸中裁减一部分作为新棋盘,当然,他希望这个棋盘尽可能的大。

    不过小Q还没有决定是找一个正方形的棋盘还是一个矩形的棋盘(当然,不管哪种,棋盘必须都黑白相间,即相邻的格子不同色),所以他希望可以找到最大的正方形棋盘面积和最大的矩形棋盘面积,从而决定哪个更好一些。

    于是小Q找到了即将参加全国信息学竞赛的你,你能帮助他么?

    输入输出格式

    输入格式:

    包含两个整数(N)(M),分别表示矩形纸片的长和宽。接下来的(N)行包含一个(N imes M)(01)矩阵,表示这张矩形纸片的颜色((0)表示白色,(1)表示黑色)。

    输出格式:

    包含两行,每行包含一个整数。第一行为可以找到的最大正方形棋盘的面积,第二行为可以找到的最大矩形棋盘的面积(注意正方形和矩形是可以相交或者包含的)。

    输入输出样例

    输入样例#1:

    3 3
    1 0 1
    0 1 0
    1 0 0

    输出样例#1:

    4
    6

    说明

    对于(20\%)的数据,(N, M ≤ 80)

    对于(40\%)的数据,(N, M ≤ 400)

    对于(100\%)的数据,(N, M ≤ 2000)

    题意: 给出一个(n*m)(01)矩阵,要求出其中最大的(01)相间的正方形和矩形.

    题解: 正方形还是比较好求的,如果不会可以先看看这道题:最大正方形II.

    但是如果变成了矩形,DP在这里就不行了,因为在转移状态的时候无法记录长和宽.

    所以这里引入了一个神奇的算法:单调栈.

    单调栈是什么呢?

    说简单点,就是一个栈,栈内元素是单调(递增或递减)的.

    那么它能干什么呢?

    它支持查询一个元素后面比它大/小的第一个元素的大小.

    那么要怎么样实现查询的过程呢?

    假设我们要维护一个单调上升的栈,这里我们拿一个数列举个栗子:a={2, 4, 1, 3, 2}

    • 首先栈为空,2入栈
    • 然后处理4,此时检查栈顶与该元素的大小关系,发现2<4,4可以直接入栈.
    • 处理1,此时栈顶4比1大,先记录4右边第一个比它小的元素是1,然后将4弹出栈,此时栈顶2仍然大于1,记录2右边第一个比它小的元素是1,将2弹出栈,最后将1入栈.
    • 处理3,栈顶1<3,直接将3入栈.
    • 处理2,栈顶3>2,记录3右边第一个比它小的元素是2,将3出栈,将2入栈.
    • 此时所有元素都已经入栈完了,检查栈是否为空,此时栈内的元素右边没有比它小的元素.

    根据这个过程模拟,可以在(O(n))的时间内求出一个元素后面比它大/小的第一个元素的大小.

    因为每个元素都只会入栈/出栈一次,所以复杂度是(O(n))的.

    那么跟这道题又有什么关系呢?

    要求出一个合法的矩阵是很麻烦的,但是我们可以先将矩阵分成一个个长条.然后再动态计算可以得到的矩形的面积最大值.

    我们可以先枚举一个行,那么在这一行中,每一列的一个点都可以向上延伸一定的长度(当然这个可以从上一行的状态直接推过来),也就是上面讲的一个个长条.显然如果先有一根长条,后面又进来一根短一点的矩形,那么之前那根较长的矩形也无法算进对后面的贡献中.

    也就是说,我们如果维护一个单调上升的栈,那么当一个长条矩形要出栈的时候,要计算它和后面组成的最大面积的时候,可以直接用这个长条矩形的长度乘以两个矩形之间的间隔.

    可能讲得不太清楚,可以自己再画图理解一下.我才不会说是我懒得画图了

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 2000+5;
    #define x (h[stk[top]])
    #define y (pos-stk[top-1]-1)
    #define z (min(x, y))
    
    int n, m, a[N][N], h[N], top = 0, stk[N], ans1 = 0, ans2 = 0;
    
    int main(){
        //freopen("data.in", "r", stdin);
        ios::sync_with_stdio(false);
        cin >> n >> m;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++) cin >> a[i][j];
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                if(i > 1 && a[i][j] != a[i-1][j]) h[j]++;
                else h[j] = 1;
            }
            int pos = 1;
            while(pos <= m){
                top = 0, stk[top] = pos-1, stk[++top] = pos++;
                while(pos <= m && a[i][stk[top]] != a[i][pos]){
                    while(top && h[pos] < h[stk[top]])
                        ans1 = max(ans1, z*z), ans2 = max(ans2, x*y), top--;
                    stk[++top] = pos++;
                }
                while(top) ans1 = max(ans1, z*z), ans2 = max(ans2, x*y), top--;
            }
        }
        cout << ans1 << endl << ans2 << endl;
        return 0;
    }
    
  • 相关阅读:
    ES5和ES6中的静态方法、类、单例模式
    Koa 应用生成器以及 Koa 路由模块化
    封装 Koa操作Mongodb数据库的DB类库
    Koa Session 的使用
    Koa 中 Cookie 的使用
    koa art-template 模板引擎
    koa koa-static 静态资源中间件
    koa post 提交数据 koa-bodyparser 中间件的使用
    koa ejs 模板引擎
    详解express与koa中间件执行顺序模式分析
  • 原文地址:https://www.cnblogs.com/BCOI/p/9716740.html
Copyright © 2011-2022 走看看