[P1169] 棋盘制作 &悬线法学习笔记

学习笔记 悬线法

  • 最大子矩阵问题:

          在一个给定的矩形中有一些障碍点,找出内部不包含障碍点的,边与整个矩形平行或重合的最大子矩形。

          极大子矩型:无法再向外拓展的有效子矩形

          最大子矩型:最大的一个有效子矩形

          特别的,在一个有障碍点的矩形中,最大子矩形一定是极大子矩形 

  •  悬线法

           悬线:上端覆盖了一个障碍点或者到达整个矩形上边界的有效线段

           每个悬线上的点的与底部的点一一对应,矩形中每一个点(矩形顶部点除外)都对应了一条悬线。

           如果把一条悬线向左右两个方向尽可能的移动,那么就得到了一个矩形。

           注意:悬线对应的矩型不一定是极大子矩阵,因为悬线定义中固定了悬线的下边界,故而,悬线左右移动所得到的矩形无法向下扩展。

  • 悬线法的实现

      三个重要的元素:

  1. heighti,j :表示以( i ,j )为底的悬线的高 (初始化为1)
  2. lefti,j        :表示向左最多能移动到的位置  (初始化为j)
  3. righti,j     : 表示向右最多能移动到的位置   (初始化为j)

       其中的left,right要视题目要求进行进一步的初始化,如例题

      转移:

      如果点 (i-1, j) 不是障碍点,那么,以 (i,j) 为底的悬线就等于以 (i-1,j) 为底的悬线加点 (i,j) 到点 (i - 1,j)      的线段。因此, height_{i,j}=height_{i-1,j}+1 。

 

 

       

        当然还要注意左右边界的问题

       以上图片转自  https://zhuanlan.zhihu.com/p/46382722


        画个图理解一下

        那么计算面积就轻而易举

        

      对于以点 (i, j) 为底的悬线对应的子矩形,其面积计算为

{(right_{i,j}-left_{i,j})\times height_{i,j}}

    问题解:ans = max \begin{cases} (right_{i,j}-left_{i,j})*height_{i,j} \end{cases}

    时间复杂度: O(nm) ;空间复杂度: O(nm)

 例题:luogu P1169 棋盘制作

直接上代码

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 #define maxn 2010
 5 #define re register
 6 using namespace std;
 7 int n,m,ans1,ans2;
 8 int map[maxn][maxn],height[maxn][maxn];
 9 int l[maxn][maxn],r[maxn][maxn];
10 int main()
11 {
12     scanf("%d%d",&n,&m);
13     for(re int i=1;i<=n;++i)
14      for(re int j=1;j<=m;++j)
15      {
16          scanf("%d",&map[i][j]);
17          height[i][j]=1;
18          l[i][j]=r[i][j]=j;
19      }
20     for(re int i=1;i<=n;++i)
21      for(re int j=2;j<=m;++j)
22      {
23          if(map[i][j]!=map[i][j-1])
24          l[i][j]=l[i][j-1];
25      }
26     for(re int i=1;i<=n;++i)
27      for(re int j=m-1;j>=1;j--)
28      {
29          if(map[i][j]!=map[i][j+1])
30          r[i][j]=r[i][j+1];
31      }
32     //以上为初始化
33     for(re int i=1;i<=n;++i)
34       for(re int j=1;j<=m;++j)
35       {
36           if(i>1&&map[i][j]!=map[i-1][j])
37           {
38               height[i][j]=height[i-1][j]+1;
39               l[i][j]=max(l[i][j],l[i-1][j]);
40               r[i][j]=min(r[i][j],r[i-1][j]);
41         }
42         int a=r[i][j]-l[i][j]+1;
43         int b=min(height[i][j],a);
44         ans1=max(ans1,a*height[i][j]);//最大矩形 
45         ans2=max(ans2,b*b);//最大正方形 
46       }
47       printf("%d\n%d",ans2,ans1); 
48     return 0;
49 }

注:部分内容转载自  
Flavius Buffon:悬线法用来求解最大子矩形问题 同时也是参考文献

转载于:https://www.cnblogs.com/Liuz8848/p/10705642.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值