题意:给你平面上的n个点,找到一个矩形使得边界上包含尽量多的点,并输出最多的点数
我们分析后可以发现除非所有的输入点都在同一行/列上,最优矩阵的4条边都至少有一个点,因此我们可以枚举四条边界所穿过的点,然后统计点数,O(n^5)
可以考虑部分枚举,即只枚举矩阵的上下边界,用其他方法确定左右边界
对于一个竖线i,我们用l[i]表示竖线左边位于上下边界的点数(但是不算位于这条线上的点)
on[i]表示竖线上位于上下边界之间的点数(不统计位于上下边界的点)
on2[i]表示竖线上位于上下边界之间的点数(要统计位于上下边界的点)
所以给定左右边界i,j时,矩形上点数为l[j]-l[i]+on[i]+on2[j],当右边界j一定时,应当维护on[i]-l[i]的最大值
枚举完上下边界后,我们先从左到右扫描所有点计算l[i],on[i],on2[i].然后枚举右边界j同时维护on[i]-l[i](i<j)的max,顺便更新答案就解决了
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=105,inf=1e9;
inline void _read(int &x){
char t=getchar();bool sign=true;
while(t<'0'||t>'9')
{if(t=='-')sign=false;t=getchar();}
for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
if(!sign)x=-x;
}
struct wk{
int x,y;
bool operator < (const wk& a)const{
return x<a.x;
}
}p[maxn];
int n,m,y[maxn],l[maxn],on[maxn],on2[maxn];
int main(){
int cases=0,i,j,up,down;
while(scanf("%d",&n)&&n){
bool flag=1;
for(i=1;i<=n;i++){
_read(p[i].x);_read(p[i].y);
y[i]=p[i].y;
}
sort(p+1,p+1+n);
sort(y+1,y+1+n);
int num=unique(y+1,y+1+n)-y;//删除所有高度相同的点
num--;
if(num<=2){
printf("Case %d: %d\n",++cases,n); //只有两种以下的高度,可以用一个矩形覆盖所有点
continue;
}
int ans=0;
for(down=1;down<=num&&flag;down++)
for(up=down+1;up<=num;up++){
int k=0;
for(i=1;i<=n;i++){
if(i==0||p[i].x!=p[i-1].x){
on[++k]=on2[k]=0;
l[k]=l[k-1]-on[k-1]+on2[k-1];
}
if(p[i].y>y[down]&&p[i].y<y[up])on[k]++;
if(p[i].y>=y[down]&&p[i].y<=y[up])on2[k]++;
}
if(k<=2){
printf("Case %d: %d\n",++cases,n);//道理同上
flag=0;
}
if(!flag)break;
int maxx=0;
for(i=1;i<=k;i++){//注意下面的赋值顺序
ans=max(ans,l[i]+on2[i]+maxx);
maxx=max(maxx,on[i]-l[i]);
}
}
if(flag)printf("Case %d: %d\n",++cases,ans);
}
}