【题解】洛谷P1169 棋盘制作(栈,dp)

想要解决这个问题,我们不妨看一个类似的问题,就是给你n个数,代表位置n上积木的高度,求其最大面积。为了让时间复杂度控制在 O(N)之内,我们需要用栈来解决这个问题。设定h[n+1]=0来让栈最后里面的元素可以自动退栈,栈里存放高度的单调递增序列的坐标,当读入的高度比栈顶元素高度小时,那就记录下栈顶元素的高度,用当前坐标减去栈顶元素底下元素的坐标+1得到宽度,相乘记录最大值,然后将栈顶元素出栈,重复此过程。最后输出答案即可。

对于这道题的01交替,也可以把它看做类似的问题,设h[j]代表第j列中01交替出现的个数,注意这里跟上个问题有点区别,我们读到相同的00时应当把坐标更新,因为最大面积有可能在棋盘内部而不是边缘。设指针为p,当p<=m并且横向两个相邻的格子不是同一个数时,我们才对栈进行操作,操作方法类似上面的第一个问题,如果两个横向相邻的格子相同,我们就需要记录答案了,思路和第一个问题也类似,注意如果求正方形的话需要记录长度和宽度的最小值相乘即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
int n,m;
int a[2010][2010];
int h[2010];
int stack[2010];
int top=0;
int ans1,ans2;

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(i==1) h[j]=1;
			else 
			{
				if(a[i][j]==a[i-1][j])
				{
					h[j]=1;
				}
				else h[j]++;
			}
		}
		int p=1;
		while(p<=m)
		{
			top=0;
			stack[0]=p-1;
			stack[++top]=p;
			p++;
			
			while(p<=m&&a[i][p]!=a[i][p-1])
			{
				while(top!=0&&h[stack[top]]>h[p])
				{
					int hh=h[stack[top]];
					int ww=p-stack[top-1]-1;
					int q=min(hh,ww);
					ans1=max(ans1,q*q);
					ans2=max(ans2,hh*ww);
					top--;
				}
				stack[++top]=p;
				p++;
			}


			while(top!=0)
			{
				int hh=h[stack[top]];
				int ww=p-stack[top-1]-1;
				int q=min(hh,ww);
				ans1=max(ans1,q*q);
				ans2=max(ans2,hh*ww);
				top--;
			}
		}
	}

	cout<<ans1<<endl;
	cout<<ans2<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/rem_inory/article/details/81087996
今日推荐