最大子图形问题

CODEVS1159最大全0子矩阵

题目描述 Description

在一个0,1方阵中找出其中最大的全0子矩阵,所谓最大是指O的个数最多。

思路:这个题最朴素的n^6的算法,超时美美的。。。然后想优化,从一个点向上方、左方、右方扩展,首先更新这个点向上能有多少个0h0,然后找左右h比h0大的作为左右边界,然后计算这个矩形的面积,最后输出最大值。。。这种构造的美丽算法,真心。。。

比较: 最大全0子正方形:f[i][j](以i,j为右下角的最大正方形的边长)=min(f[i-1][j],f[i][j-1],f[i-1][j-1]),这里用了正方形的特性,所以和矩形的求法不同。
这属于dp中的重要分支,最大子图形问题,详细的讲解可以参考下面的网址。。。真心丧病。。。 
http://www.docin.com/p-46970779.html 

code:



#include<iostream>



#include<cstdio>



using namespace std;



int li[2001]={0},ri[2001]={0},hi[2001]={0},a[2001][2001]={0};



int main()



{



int n,i,j,ans=0;



scanf("%d",&n);



for (i=1;i<=n;++i)



  for (j=1;j<=n;++j)



    scanf("%d",&a[i][j]);



for (i=1;i<=n;++i)



{



for (j=1;j<=n;++j)



{



  if (a[i][j]==0) ++hi[j];



  else hi[j]=0;



  li[j]=ri[j]=j;



    }



    for (j=2;j<=n;++j)



      if (a[i][j]==0)



        while (hi[li[j]-1]>=hi[j])



          li[j]=li[li[j]-1];



for (j=n-1;j>=1;--j)



  if (a[i][j]==0)



        while (hi[ri[j]+1]>=hi[j])



          ri[j]=ri[ri[j]+1];



    for (j=1;j<=n;++j)



      if (a[i][j]==0)



        ans=max(ans,(ri[j]-li[j]+1)*hi[j]);



}



cout<<ans<<endl;



}
RZUC Code

 

 

CODEVS1259最大正方形子矩阵

题目描述  Description

在一个01矩阵中,包含有很多的正方形子矩阵,现在要求出这个01矩阵中,最大的正方形子矩阵,使得这个正方形子矩阵中的某一条对角线上的值全是1,其余的全是0。

 

思路:做了好几个有关的最大子阵的问题,发现还是有些困难,做这个题想了好久,发现其实很简单,利用全0子矩阵的思路和正方形的思路就可以比较简单的写出dp方程。预处理一个点上方hi,左方li和右方ri0的个数(不包含这个点本身)。

  f[i][j]=min(f[i-1][j-1]+1,min(li[i][j]+1,hi[i][j]+1))

第一个比较容易错的地方就来,每次对于能更新的f[i][j]的位置要求在map中为1,否则就不能构成要求的正方形;

其次就是题目中要求对角线为1,一个正方形有两条对角线,都应该考虑到,根据f数组的更新可以同理写出;

在预处理的时候细心,注意这个点和周围点的关系就可以了。

#include<iostream>

#include<cstdio>

using namespace std;

int map[1010][1010]={0},li[1010][1010]={0},ri[1010][1010]={0},hi[1010][1010]={0},f[1010][1010]={0},g[1010][1010]={0};

int main()

{

    int n,m,i,j,ans=0;

    cin>>n>>m;

    for (i=1;i<=n;++i)

    {

        for (j=1;j<=m;++j)

        {

            scanf("%d",&map[i][j]);

            hi[i][j]=hi[i-1][j];

            li[i][j]=li[i][j-1];

            if (map[i-1][j]==0) ++hi[i][j];

            else hi[i][j]=0;

            if (map[i][j-1]==0&&j>1) ++li[i][j];

            else li[i][j]=0; 

        }

        for (j=m-1;j>=1;--j)

        {

            ri[i][j]=ri[i][j+1];

            if (map[i][j+1]==0) ++ri[i][j];

            else ri[i][j]=0;

        }

    }

    for (i=1;i<=n;++i)

    {

        for (j=1;j<=m;++j)

          if (map[i][j]==1)

          {

            f[i][j]=min(f[i-1][j-1]+1,min(li[i][j]+1,hi[i][j]+1));

            if (f[i][j]>ans) 

              ans=f[i][j];

          }

        for (j=m;j>=1;--j)

          if (map[i][j]==1)

          {

            g[i][j]=min(g[i-1][j+1]+1,min(ri[i][j]+1,hi[i][j]+1));

            if (g[i][j]>ans)

              ans=g[i][j];

          }

    }

    cout<<ans<<endl;

}
RZUC Code

从网上看到了一个很全的子图形问题的Word,分享一下:http://www.docin.com/p-351795539.html

 

 

tyvj1563最大正方形

 

 

思路:这个题目很特殊,要求最大正方形中相邻两点的颜色不同,所以可以读图的时候进行处理,隔一个变一次(使这个位置上0、1互换),这样就转化成了矩阵中的最大全0或全1子正方形了,非常简单的dp解决

  f[i][j]=min(f[i-1][j-1],min(f[i-1][j],f[i][j-1]))+1;(全0,先判断map[i][j]=0) 全1同理;

最大子图形问题的众多变式都应能转化为基本的求正方形、矩形等问题,得以比较简单的解决。看来noip后要找时间好好研究了。。。

你可能感兴趣的:(问题)