zoukankan      html  css  js  c++  java
  • ZJOI2007 棋盘制作

    传送门

    DP找给定区域内最大符合条件的矩形/正方形。这里有一种新的方法———悬线法。

    悬线的定义:每个点(i,j),都对应一条悬线,当前点是悬线的下端,悬线的上端为一个障碍点或者矩形的上边界。

    所以一个符合条件的矩形,我们只要使用悬线法计算出这条悬线移动到不合法位置时的边界即可。

    (注意left和right似乎在iostream库中是保留字)

    用lef[i][j]表示从点(i,j)引出的悬线能拓展到的最左边的位置,righ[i][j]表示从点(i,j)引出的悬线能拓展到最右边的位置。up[i][j]表示这条悬线能向上拓展的最大长度。

    这样我们可以先预处理出每条悬线的lef,righ,只要左右两格不同就可以进行转移。

    之后我们就得到递推式:

    left[i][j]=max(left[i][j],left[i-1][j];
    right[i][j]=min(right[i][j],right[i-1][j];
    注意这里要考虑上一行的情况,是因为up的原因。
    之后从上向下DP,每次处理一下当前的最大合法矩形即可。
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    //#include<iostream>
    #include<cmath>
    #include<queue>
    #include<set>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 50005;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    int n,m,g[2005][2005],up[2005][2005],lef[2005][2005],right[2005][2005];
    int ans1,ans2;
    
    int main()
    {
        n = read(),m = read();
        rep(i,1,n)
        rep(j,1,m) g[i][j] = read(),lef[i][j] = right[i][j] = j,up[i][j] = 1;
        rep(i,1,n)
        rep(j,2,m) if(g[i][j] != g[i][j-1]) lef[i][j] = lef[i][j-1];
        rep(i,1,n)
        per(j,m-1,1) if(g[i][j] != g[i][j+1]) right[i][j] = right[i][j+1];
        rep(i,1,n)
        rep(j,1,m)
        {
        if(i > 1 && g[i][j] != g[i-1][j])
        {
            lef[i][j] = max(lef[i][j],lef[i-1][j]);
            right[i][j] = min(right[i][j],right[i-1][j]);
            up[i][j] = up[i-1][j]+1;
        }
        int lena = right[i][j] - lef[i][j] + 1;
        int lenb = min(lena,up[i][j]);
        ans1 = max(ans1,lenb*lenb);
        ans2 = max(ans2,lena*up[i][j]);
        }
        printf("%d
    %d
    ",ans1,ans2);
        return 0;
    }
     
  • 相关阅读:
    Git 学习笔记(W,I,P)
    DirectX API 编程起步 #01 项目设置
    #1004 Let the Balloon Rise
    #1003 Max Sum
    人生的第一个博客(●'◡'●)ノ♥--开博典礼
    2053——switch game
    在Activity间传递数据的四种方法及返回结果
    安卓学习第38课——ProgressDialog
    安卓学习第37课——DatePickerDialog、TimePickerDialog
    安卓学习第36课——PopupWindow
  • 原文地址:https://www.cnblogs.com/captain1/p/9591973.html
Copyright © 2011-2022 走看看