给出平面上的n个点,找一个矩形,使得边界上包含尽量多的点。
【输入格式】
输入的第一行为数据组数T。每组数据的第一行为整数n(1≤n≤100);以下n行每行两个整数,即各个点的坐标(坐标均为绝对值不超过109的整数)。输入结束标志为n=0。
【输出格式】
对于每组数据,输出边界点个数的最大值。
先贴题解的精妙预处理:
不难发现,除非所有输入点都在同一行或者同一列上(此时答案为n),最优矩形的4条边都至少有一个点(一个角上的点同时算在两条边上)。这样,我们可以枚举4条边界所穿过的点,然后统计点数。这样做的时间复杂度为O(n5)(统计点数还需要O(n)时间),无法承受。
和《子序列》一题类似,可以考虑部分枚举,即只枚举矩形的上下边界,用其他方法确定左右边界,过程如图1-31所示。
对于竖线i,我们用left[i]表示竖线左边位于上下边界上的点数(注意,不统计位于该竖线上的点),on[i]和on2[i]表示竖线上位于上下边界之间的点数(区别在于on[i]不统计位于上下边界上的点数,而on2[i]要统计)。这样,给定左右边界i和j时,矩形边界上的点数为left[j]-left[i]+on[i]+on2[j]。当右边界j确定时,on[i]-left[i]应最大。
枚举完上下边界后,我们先花O(n)时间按照从左到右的顺序扫描一遍所有点,计算left、on[i]和on2[i]数组,然后枚举右边界j,同时维护on[i]-left[i](i<j)的最大值。这一步本质上等价于例题《开放式学分制》。
再讲解一下这题的离散化处理
给每个点一个新的坐标 x坐标 为其原x坐标的排序后位置
y坐标 为其原y坐标的排序后位置
对于对距离不敏感的点集问题 这样十分方便处理问题
贴代码:
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <ctime> #include <algorithm> #include <iostream> #include <sstream> #include <string> #define oo 0x13131313 const int maxn=100+5; using namespace std; struct point { int x,y; }; point P[maxn]; int N; int YN,XN; int ans; int FF[maxn][maxn]; int CE[maxn][maxn]; int UP[maxn][maxn]; void input() { YN=0;XN=0; memset(FF,0,sizeof(FF)); memset(CE,0,sizeof(CE)); memset(UP,0,sizeof(UP)); for(int i=1;i<=N;i++) scanf("%d%d",&P[i].x,&P[i].y); } int cmp1(const void *i,const void *j) { point *ii=(point *)i,*jj=(point *)j; return ii->x-jj->x; } void getXN() { int i; qsort(P+1,N,sizeof(P[1]),cmp1); for(i=1;i<=N;i++) { if(P[i].x!=P[i-1].x) { XN++; P[i-1].x=XN-1; } else P[i-1].x=XN; } P[N].x=XN; } int cmp2(const void *i,const void *j) { point *ii=(point *)i,*jj=(point *)j; return ii->y-jj->y; } void getYN_FF() { int i; qsort(P+1,N,sizeof(P[1]),cmp2); for(i=1;i<=N;i++) { if(P[i].y!=P[i-1].y) { YN++; P[i-1].y=YN-1; } else P[i-1].y=YN; FF[P[i-1].x][P[i-1].y]++; } P[N].y=YN; FF[P[N].x][P[N].y]++; } void get_UPCE() { for(int i=1;i<=XN;i++) for(int j=1;j<=YN;j++) { CE[i][j]=CE[i][j-1]+FF[i][j]; UP[i][j]=UP[i-1][j]+FF[i][j]; } } int On[maxn],Left[maxn],On2[maxn]; void get_On_Left_On2(int a,int b) { memset(On,0,sizeof(On)); memset(Left,0,sizeof(Left)); memset(On2,0,sizeof(On2)); for(int i=1;i<=YN;i++) { On[i]=UP[b-1][i]-UP[a][i]; On2[i]=UP[b][i]-UP[a-1][i]; Left[i]=CE[a][i-1]+CE[b][i-1]; } } void solve() { ans=0; int tempans=0,tempi=0; for(int i=1;i<=XN;i++) for(int i2=i+1;i2<=XN;i2++) { get_On_Left_On2(i,i2); tempans=0; for(int j=1;j<=YN;j++) { if(ans<Left[j]+On2[j]+tempans) ans=Left[j]+On2[j]+tempans; if(tempans<On[j]-Left[j]) tempans=On[j]-Left[j]; } } } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int Case=0; while(cin>>N&&N) { Case++; input(); if(N<=3) { printf("Case %d: %d\n",Case,N); continue; } getXN(); getYN_FF(); get_UPCE(); solve(); printf("Case %d: %d\n",Case,ans); } }