题目大意
给定平面上的n个点,找一个矩形,使得边界上包含尽量多的点。
分析
不难发现除非所有的点都在同一条直线上,否则矩阵的四条边至少会有一个点(一个角上的点同时算在两条边上).这样,我们枚举4条边界所穿过的点,然后统计点数,这样做的复杂符很高,数据量无法承受。
和子序列一样我们考虑部分枚举,只枚举矩形的上下界。用其他方法定义左右边界。
当一个矩形的上下边界确定后,我们来计算左右边界点。我们定义left(i)为以i为右边界的上下边界的数,定义on(i)和on2(i)为边界本身不属于上下边界的点以及算上下边界的点;这样对于一个矩形,总点数为left(j)-left(i)+on(i)+on(j) (j>i) 我们进一步的优化 当边界j 确定是 on(i)-left(i)应为最大
上代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#define maxn 100+10
using namespace std;
struct po {
int x, y;
bool operator <(const po& a) const
{
return x < a.x;
}
};
po star[maxn];
int le[maxn], on[maxn], on2[maxn];
int y[maxn];
int n;
int solve()
{
int ymin, ymax;
sort(star, star + n);
sort(y, y + n);
//print();
int num = unique(y, y + n)-y;
//cout << num<<endl;
if (num <= 2)
return n;
int ans=0, M=0;
for (int a = 0; a <num; a++)
{
for (int b = a + 1; b < num; b++)
{
int k = 0;
ymin = y[a], ymax = y[b];
le[0] = 0;
for (int i = 0; i < n; i++)
{
if (i == 0 || star[i].x != star[i - 1].x) //一条新的竖线
{
k++;
on[k] = on2[k] = 0;
le[k] =le[k - 1] + on2[k - 1] - on[k-1];//为什么k要等于0;
}
if (star[i].y > ymin&&star[i].y < ymax) on[k]++;
if (star[i].y >= ymin&&star[i].y <= ymax) on2[k]++;
}
if (k <= 2)
return n;
M = 0;
for (int j = 1; j <=k; j++)
{
ans = max(ans, le[j] + on2[j] + M);
M = max(M, on[j] - le[j]);
}
}
}
return ans;
}
int main()
{
int k = 1;
while (cin >> n && n != 0)
{
for (int i = 0; i < n; i++)
{
cin >> star[i].x >> star[i].y;
y[i] = star[i].y;
}
printf("Case %d: %d\n", k++, solve());
}
return 0;
}