平面上给你一些具有黑或白颜色的点,让你设置一个隔板,使得隔板一侧的黑点加上另一侧的白点数最多。隔板上的点可视作任意一侧。
易知一定存在一个隔板穿过两个点且最优,因此可以先固定以一个点为原点,将其他点中的黑点移到对称的位置,并将所有点按极角排序,然后双指针遍历其他点,利用尺取法维护一个角度不超过180°的区间(算角度是否大于180°可以用叉积)。对每个点都算一遍,取最大区间长度即为最终答案。
区间尺取部分网上的代码基本都的“lr表示法”,比较冗长,我这里给出了“lw表示法”(w代表区间长度),代码简洁了许多,只是因为之前忘了在l增加的时候改变w的值而WA到怀疑人生...
另外注意n<=3时需要特判。(貌似只用特判n=1,但n=3的时候答案就是n,可以直接跳过求解过程)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 typedef double db; 6 const int N=1000+10; 7 const db eps=1e-10; 8 struct P { 9 int col; 10 db x,y,rad; 11 bool operator<(const P& b)const {return rad<b.rad;} 12 } p[N],q[N]; 13 int n,m,ans; 14 db cross(P a,P b) {return a.x*b.y-a.y*b.x;} 15 16 int main() { 17 while(scanf("%d",&n)&&n) { 18 for(int i=0; i<n; ++i)scanf("%lf%lf%d",&p[i].x,&p[i].y,&p[i].col); 19 if(n<=3)ans=n; 20 else { 21 ans=0; 22 for(int i=0; i<n; ++i) { 23 m=0; 24 for(int j=0; j<n; ++j)if(j!=i) { 25 q[m]= {p[j].col,p[j].x-p[i].x,p[j].y-p[i].y}; 26 if(q[m].col)q[m].x=-q[m].x,q[m].y=-q[m].y; 27 q[m].rad=atan2(q[m].y,q[m].x); 28 m++; 29 } 30 sort(q,q+m); 31 for(int l=0,w=0; l<m; ++l,--w) { 32 for(; w<m&&cross(q[l],q[(l+w)%m])>=0; ++w); 33 ans=max(ans,w+1); 34 } 35 } 36 } 37 printf("%d\n",ans); 38 } 39 return 0; 40 }