You are observing a distant galaxy using a telescope above the Astronomy Tower, and you think that a rectangle drawn in that galaxy whose edges are parallel to coordinate axes and contain maximum star systems on its edges has a great deal to do with the mysteries of universe. However you do not have the laptop with you, thus you have written the coordinates of all star systems down on a piece of paper and decide to work out the result later. Can you finish this task?

Input
There are multiple test cases in the input file. Each test case starts with one integerN ,
(1N
100) , the number of star systems on the telescope.
N lines follow, each line consists of two integers: theX and
Y coordinates of theK -th planet system. The absolute value of any coordinate is no more than109 , and you can assume that the planets are arbitrarily
distributed in the universe.
N = 0 indicates the end of input file and should not be processed by your program.
Output
For each test case, output the maximum value you have found on a single line in the format as indicated in the sample output.
Sample Input
10 2 3 9 2 7 4 3 4 5 7 1 5 10 4 10 6 11 4 4 6 0
Sample Output
Case 1: 7
找一个矩形,让边界上包含最多的点。
如果枚举四个边界,统计数目,复杂度O(N^5)(统计需要O(N)),时间太长。
联想到一个问题,N个数排成一列,找出右边的数减左边的数的最大值,只需要O(N)的时间枚举右边的数,因为从左到右枚举右边的数的时候,可以顺便更新到目前为止遇到的最小值,也就是每次只要用枚举的数减去它左边的最小值就行了。
这个题其实也是上面问题的变形,可以枚举上下边界,再枚举右边界,维护最大答案。如果设on[i]为第i条竖线在上下边界内(不包括)的点的数量,on2[i]为第i条竖线在上下边界内(包括)的点的数量,l[i]为第i条竖线左边(不包括这条竖线上的)在上下边界上点的总数。那么若以i,j为左右边界,点数为on2[j]+l[j]-l[i]+on1[i],所以从左向右枚举右边界的时候,更新目前遇到的on1[i]-l[i]的最大值就不需要在枚举左边界了。
算出on,on2,l需要O(N)的时间扫一遍,在已按x排好序的情况下,若这个x和上个x不相等,说明竖线又多了一条k,l[k]=l[k-1]+on2[k-1]-on[k-1]。根据判断y是否在上下边界内来算on,on2。
结构体按x排序。那怎么枚举上下边界呢?用一个数组y[i]记录第i个点的y坐标,从小到大排序,我也是才知道还有这个函数,unique,能把一个序列连续相同的只留一个,剩下的排到序列后面,返回起始地址加上有多少个不同的数,比如1,1,2调用这个函数就变成1,2,1,但是1,2,1调用就不会变化,因为1不连续。
目前做了2个部分枚举的题目,还不是很熟,都需要一些递推,不好想。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<sstream>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define INF 0x3f3f3f3f
#define MAXN 110
#define MAXM 60
#define eps 1e-9
#define pii pair<int,int>
using namespace std;
int N,y[MAXN],on[MAXN],on2[MAXN],l[MAXN];
struct point{
int x,y;
bool operator < (const point &a) const{
return x<a.x;
}
}p[MAXN];
int solve(){
int ret=0;
sort(p,p+N);
sort(y,y+N);
int m=unique(y,y+N)-y; //有m条横线
if(m<=2) return N;
for(int a=0;a<m;a++) //枚举上下界
for(int b=a+1;b<m;b++){
int miny=y[a],maxy=y[b],k=0;
memset(on,0,sizeof(on));
memset(on2,0,sizeof(on2));
memset(l,0,sizeof(l));
for(int i=0;i<N;i++){ //递推求出l,on,on2
if(!i||p[i].x!=p[i-1].x){
k++;
if(k>1) l[k]=l[k-1]+on2[k-1]-on[k-1];
}
if(p[i].y<maxy&&p[i].y>miny) on[k]++;
if(p[i].y<=maxy&&p[i].y>=miny) on2[k]++;
}
if(k<=2) return N;
int MAX=0;
for(int i=1;i<=k;i++){ //从左往右枚举右边界,维护最大值
ret=max(ret,l[i]+on2[i]+MAX);
MAX=max(MAX,on[i]-l[i]);
}
}
return ret;
}
int main(){
freopen("in.txt","r",stdin);
int cas=0;
while(scanf("%d",&N),N){
for(int i=0;i<N;i++){
scanf("%d%d",&p[i].x,&p[i].y);
y[i]=p[i].y;
}
printf("Case %d: %d\n",++cas,solve());
}
return 0;
}