这道题,我们一开始就能想到O(n^5)的算法---n^4找矩阵的两个对顶角,n用来查找。但因为n<=100,n^5=10^10,所以我们必须用优化算法。我们先枚举上下界(这两条线上面要有点。用了离散化的思想),即局部枚举,然后在用n的时间一列一列的算(上面有点的。用了离散化的思想),最终算法O(n^3)
#include<iostream>
#include<cstdio>#include<algorithm>
using namespace std;
struct wo{
int x,y;
};
int cmp(wo a,wo b){
return a.x<b.x;
}//按行排序
wo a[105];
int n,m;
int y[105],on[105],on2[105],left1[105];//left是系统内部的一个名字
int solve(){
sort(a+1,a+n+1,cmp);
sort(y+1,y+n+1);
m=unique(y+1,y+n+1)-(y+1);//去重,计算出去重后直线x=l的个数
if(m<=2)return n;
int ans=0;
for(int i=1;i<m;i++){
for(int j=i+1;j<=m;j++){
int minn=y[i],maxn=y[j];//枚举上边界和下边界
int k=0;
for(int l=1;l<=n;l++){
if(l==1||a[l].x!=a[l-1].x){
k++;//新一条直线了
on[k]=on2[k]=0;
left1[k]=left1[k-1]+on2[k-1]-on[k-1];//计算当前这条直线
//左边(包括自己)有多少个点在上下边界上;
}
if(a[l].y>minn&&a[l].y<maxn)on[k]++;//计算当前直线上在上下边界(不包括)内有多少个点
if(a[l].y>=minn&&a[l].y<=maxn)on2[k]++;// 计算当前直线上在上下边界(包括)内有多少个点
}
if(k<=2)return n;//上下两条之间即可覆盖所有点则全都能被覆盖
int count1=0;
for(int l=1;l<=k;l++){
ans=max(ans,left1[l]+on2[l]+count1);//第l个直线在边界(矩阵的四条边)上左边有多少个点
//计算前k条直线选哪个最好(算出的是那个直线上的点数)
count1=max(count1,on[l]-left1[l]);
}
}
}
return ans;
}
int main(){
int cases=0;
while(scanf("%d",&n)!=EOF&&n){
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
y[i]=a[i].y;
}
printf("Case %d: %d ",++cases,solve());
}
return 0;
}