zoukankan      html  css  js  c++  java
  • 洛谷 1169 棋盘制作

    洛谷原题链接

    解题思路:

      这道题目主要是运用了一个叫做悬线法的方法来求极大矩阵的。

      所谓悬线法:就是维护三个数组:up[ ][ ], left_[ ][ ], right_[ ][ ]. 分别表示点(i,j) 向上方,左方,右方走能走的最远距离。

      维护方法运用了一些DP思维:

    up[i][j] = up[i - 1][j] + 1;
    left_[i][j] = min(left_[i - 1][j], j - lz);    //lz表示左边最近的障碍
    right_[i][j] = min(right_[i - 1][j], rz - j);  //rz表示右边最近的障碍

      还要注意初始化要让第0行的元素为正无穷,防止其对答案造成干扰。

      当遇到障碍点时,应先更新最近障碍位置,然后将该点的left_, right_值赋成正无穷。原因同上。

      为了方便维护lz, rz 的值,我跑了两边双重循环。。。 (复杂度依然O(nm) )

      然后可以分别将0,1当作障碍各求一个解,输出最大值。

    AC代码:

    #include <iostream>
    #include <cstdio> 
    #include <cstring>
    #include <cmath>
    
    using namespace std;
    
    const int MAXN = 2010;
    
    short ma[MAXN][MAXN];
    
    int n,m,lz,rz,ans,bns;
    int up[MAXN][MAXN];
    int left_[MAXN][MAXN];
    int right_[MAXN][MAXN];
    
    int read()
    {
        int x = 0;
        char c = getchar();
        
        while(c>'9' || c<'0')  c = getchar();
        while(c>='0' && c<='9')
            x = x*10 + c - '0',
            c = getchar();
            
        return x;
    }
    
    void color_(int c)
    {
        memset(up, 0, sizeof(up));
        memset(left_, 0, sizeof(left_));
        memset(right_, 0, sizeof(right_));
        
        for (int i = 1; i <= m; ++i)
            left_[0][i] = 999999999,
            right_[0][i] = 999999999;
        
        for (int i = 1; i <= n; ++i)
        {
            lz = 0;
            for (int j = 1; j <= m; ++j)
                if (ma[i][j] != c) 
                {
                    lz = j;
                    left_[i][j] = 99999999;
                    continue;
                }
                else
                {
                    up[i][j] = up[i - 1][j] + 1;
                    left_[i][j] = min(left_[i - 1][j], j - lz);
                }
                    
        }
            
        for (int i = 1; i <= n; ++i)
        {
            rz = m + 1;
            for (int j = m; j >= 1; --j)
                if (ma[i][j] != c) 
                {
                    rz = j;    
                    right_[i][j] = 99999999;
                    continue;
                }
                else
                    right_[i][j] = min(right_[i - 1][j], rz - j);
        }
            
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 1; j <= m; ++j)
            {
                ans = max(ans, up[i][j] * (left_[i][j] + right_[i][j] - 1));
                bns = max(bns, min(up[i][j], (left_[i][j] + right_[i][j] - 1))*min(up[i][j], (left_[i][j] + right_[i][j] - 1)));
            }
        }
    }
    
    int main()
    {
        scanf("%d %d", &n, &m);
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
            {
                scanf("%d", &ma[i][j]);
                if ((i + j) & 1) ma[i][j] = abs(ma[i][j] - 1);
            }
        ans = -1;
        bns = -1;
        color_(1);
        color_(0);
        cout << bns << endl << ans;
    }
  • 相关阅读:
    opencv c++编译
    报bug
    ssh的server安装和安装指定版本的软件的方法
    caffe修改需要的东西 6:40
    caffe修改需要的东西
    leveldb学习:DBimpl
    AndroidStudio加快Gradle速度的方法-android study之旅(103)
    hdu2222--Keywords Search+AC自己主动机模板
    ListView setOnItemClickListener无效原因分析
    Linux打包命令
  • 原文地址:https://www.cnblogs.com/yanyiming10243247/p/9343458.html
Copyright © 2011-2022 走看看