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

    我不是题目的说

    这道题运用了一种很巧妙的DP方式:悬线法

    红色为可用区域,蓝色为悬线,黄色为向两边延伸的长度

    如图,蓝色为悬线,黄色为向两边延伸的长度

    那么显然,最大子矩形的宽一定是这些黄线中最小的(证明从略)

    所以我们可以维护三个数组:

    Up[i][j]表示向上延伸的长度

    Left[i][j]表示向左能延伸到的最远横坐标

    Right[i][j]表示向右能延伸到的最远横坐标

    Code:

     1 #include<bits/stdc++.h>
     2 #define INF 0x3f3f3f3f
     3 using namespace std;
     4 int n,m,maxRec,maxSqr;
     5 int mp[2010][2010];
     6 int Up[2010][2010];
     7 int Left[2010][2010];
     8 int Right[2010][2010];
     9 inline void Init(){
    10     cin>>n>>m;
    11     for(int i=1;i<=n;i++){
    12         for(int j=1;j<=m;j++){
    13             cin>>mp[i][j];
    14             //预处理一:没啥可说的 
    15             Left[i][j]=Right[i][j]=j;
    16             Up[i][j]=1;
    17         }
    18     }
    19     //预处理二:处理边界 
    20     for(int i=0;i<=n+1;i++)mp[i][0]=mp[i][m+1]=INF;
    21     for(int j=0;j<=m+1;j++)mp[0][j]=mp[n+1][0]=INF;
    22     //预处理三:预处理Left、Right数组(黄线) 
    23     for(int i=1;i<=n;i++){
    24         for(int j=2;j<=m;j++){
    25             if(mp[i][j]!=mp[i][j-1]){
    26                 Left[i][j]=Left[i][j-1];
    27             }
    28         }
    29     }
    30     for(int i=1;i<=n;i++){
    31         for(int j=m-1;j>=1;j--){
    32             if(mp[i][j]!=mp[i][j+1]){
    33                 Right[i][j]=Right[i][j+1];
    34             }
    35         }
    36     }
    37 }
    38 inline void DP(){
    39     for(int i=1;i<=n;i++){
    40         for(int j=1;j<=m;j++){
    41             //更新 
    42             if(i>1&&mp[i][j]!=mp[i-1][j]){
    43                 Up[i][j]=Up[i-1][j]+1;
    44                 //注意这里存的是坐标所以Left取max而Right取min 
    45                 Left[i][j]=max(Left[i][j],Left[i-1][j]);
    46                 Right[i][j]=min(Right[i][j],Right[i-1][j]);
    47             }
    48             //统计矩形,正方形同理 
    49             int dis=Right[i][j]-Left[i][j]+1;
    50             maxRec=max(maxRec,Up[i][j]*dis);
    51             maxSqr=max(maxSqr,min(Up[i][j],dis)*min(Up[i][j],dis));
    52         }
    53     }
    54     cout<<maxSqr<<endl<<maxRec<<endl;
    55 }
    56 int main(){
    57     Init();
    58     DP();
    59     return 0;
    60 }

    内容来自_ajhfff_的博客(https://www.cnblogs.com/juruoajh/),未经允许,不得转载。
  • 相关阅读:
    accpet和connect设置超时
    两个模块的函数如何相互调用?
    有头结点的双向链表
    信号量PV操作实现进程间同步与互斥
    linux read write函数
    函数用指针传参挂死分析
    TCP/IP为什么需要四次握手和三次挥手
    负数在内存中的表示
    malloc的堆内存挂死原因;负数的表示
    Makefiel----no rule to make target 错误问题
  • 原文地址:https://www.cnblogs.com/juruoajh/p/12040408.html
Copyright © 2011-2022 走看看