【最大子矩形】面积

面积

问题描述:

给你一个长L,宽W的矩形纸,上面有n个黑点,你需要在这张纸上找出一个平行于坐标轴的最大矩形,使这个矩形中不包含黑点(可以在矩形边框上)。纸的一个顶点在(0,0),另一个顶点在(L,W)。

 

输入:

输入文件的第一行包含两个整数L和W,分别表示纸的长和宽。文件的第二行包含一个整数n,表示黑点的数量。以下n行每行包含两个整数x和y,表示一个黑点的坐标,可能重复。所有黑点都位于矩形纸内,即:0<=x<=L,0<=y<=W。 

 

输出:

输出文件仅一行,包含一个整数S,表示找到的矩形最大面积。

 

输入样例:

10 10

4

1 1

9 1

1 9

9 9

 

输出样例:

80

 

数据范围:

1<=L,W<=10000

对于50%的数据0<=n<=50

对于80%的数据0<=n<=200

对于100%的数据0<=n<=1000


拿到题我就以为是悬线法。但是因为可以把点放在边界上,因此左右界的更新先只用上一行的转移过来,修改完答案后,再根据这一行左右达到的最远处来转移。

而上界的转移也要单独处理,如果当前位置是障碍格,暂不修改它向上能够到达最远的位置。而到下一行时再修改。


实际上因为数据中的L、W都是极限数据,所以行不通。应该用时间复杂度和障碍点个数有关O(n^2)的算法。详细可以参见离散化的那一篇集训队论文。


简单来说,就是从一个点出发,向右移动,不断修改向上和向下能够到达的最大宽度,更新答案。注意还要从右到左,从上到下,从下到上再进行三次。

实际处理的时候要加上两个点,左上和右下,因为不一定要用障碍点来确定边界,而以矩形区域来确定。

要小心一种情况,即上下界或左右界被修正成一条线的情况。。


#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using std::sort;
using std::min;
using std::max;

struct node
{
	long x;
	long y;
};
node pos[1010];

bool cmpr1(const node& n1,const node& n2)
{
	return n1.y < n2.y;
}
bool cmpr2(const node& n1,const node& n2)
{
	return n1.x < n2.x;
}

long getint()
{
	long rs=0;bool sgn=1;char tmp;
	do tmp=getchar();
	while (!isdigit(tmp)&&tmp-'-');
	if (tmp=='-'){tmp=getchar();sgn=0;}
	do rs=(rs<<3)+(rs<<1)+tmp-'0';
	while (isdigit(tmp=getchar()));
	return sgn?rs:-rs;
}

int main()
{
	freopen("area.in","r",stdin);
	freopen("area.out","w",stdout);

	long n = getint();
	long m = getint();
	long k = getint();
	long ans = 0;

	for (long i=1;i<k+1;i++)
	{
		pos[i].x = getint();
		pos[i].y = getint();
	}
	k ++;
	pos[k].x = 0;
	pos[k].y = 0;
	k ++;
	pos[k].x = n;
	pos[k].y = m;
	sort(pos+1,pos+1+k,cmpr1);

	for (long i=1;i<k+1;i++)
	{
		long top = 0;
		long bottom = n;
		for (long j=i+1;j<k+1;j++)
		{
			ans = max(ans,(pos[j].y-pos[i].y)*(bottom-top));
			if (pos[j].y!=pos[i].y && pos[j].x <= pos[i].x)
				top = max(top,pos[j].x);
			if (pos[j].y!=pos[i].y && pos[j].x >= pos[i].x)
				bottom = min(bottom,pos[j].x);
		}
	}

	for (long i=k;i>0;i--)
	{
		long top = 0;
		long bottom = n;
		for (long j=i-1;j>0;j--)
		{
			ans = max(ans,(pos[i].y-pos[j].y)*(bottom-top));
			if (pos[j].y!=pos[i].y && pos[j].x <= pos[i].x)
				top = max(top,pos[j].x);
			if (pos[j].y!=pos[i].y && pos[j].x >= pos[i].x)
				bottom = min(bottom,pos[j].x);
		}
	}
	sort(pos+1,pos+1+k,cmpr2);

	for (long i=1;i<k+1;i++)
	{
		long left = 0;
		long right = m;
		for (long j=i+1;j<k+1;j++)
		{
			ans = max(ans,(pos[j].x-pos[i].x)*(right-left));
			if (pos[j].x!=pos[i].x && pos[j].y <= pos[i].y)
				left = max(left,pos[j].y);
			if (pos[j].x!=pos[i].x && pos[j].y >= pos[i].y)
				right = min(right,pos[j].y);
		}
	}
	for (long i=k;i>0;i--)
	{
		long left = 0;
		long right = m;
		for (long j=i-1;j>0;j--)
		{
			ans = max(ans,(pos[i].x-pos[j].x)*(right-left));
			if (pos[j].x!=pos[i].x && pos[j].y <= pos[i].y)
				left = max(left,pos[j].y);
			if (pos[j].x!=pos[i].x && pos[j].y >= pos[i].y)
				right = min(right,pos[j].y);
		}
	}

	printf("%ld",ans);

	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值