洛谷 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;
}

 

posted @ 2018-07-20 20:37  Christopher_Yan  阅读(166)  评论(0编辑  收藏  举报