面积
问题描述:
给你一个长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;
}