#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1000100; const int INF=1<<29; const double EPS=1e-10; const double Pi=acos(-1.0); struct Point { int x,y,c; double rad; friend bool operator<(Point A,Point B) { return A.rad<B.rad; } friend Point operator-(Point A,Point B) { return {A.x-B.x,A.y-B.y}; } void debug() { printf("x=%2d y=%2d c=%d ",x,y,c); } };Point p[maxn],t[maxn]; int n; bool Left(Point A,Point B) { return A.x*B.y-A.y*B.x>=0; } int solve(int k) { if(n<=2) return n; int cnt=0; REP(i,1,n){ if(i!=k){ t[cnt]=p[i]-p[k]; t[cnt].c=p[i].c; if(t[cnt].c){ t[cnt].x=-t[cnt].x; t[cnt].y=-t[cnt].y; } t[cnt].rad=atan2(t[cnt].y*1.0,t[cnt].x*1.0); cnt++; } } int res=1; sort(t,t+cnt); for(int L=0,R=0,tmp=2;L<cnt;L++){ if(L==R) R=(R+1)%cnt,tmp++; while(L!=R&&Left(t[L],t[R])) R=(R+1)%cnt,tmp++; tmp--; res=max(res,tmp); } return res; } int main() { freopen("in.txt","r",stdin); while(cin>>n,n){ REP(i,1,n) scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].c); int ans=0; REP(i,1,n) ans=max(solve(i),ans); cout<<ans<<endl; } return 0; } /** 题意: 平面上有n个点,每个点为白点或黑点,放置一隔板,使一侧的白点数+另一侧的黑点数最大。 隔板上的点可视为任意一侧。 分析: 由于最优时,隔板一定经过至少两个点,所以枚举基准点,然后再枚举隔板上的另一点确定隔板方向, 极角排序后进行划窗统计。复杂度n^2*logn。 这里有个技巧,确定基准点后,可以将所有的黑点关于基准点中心对称到另一侧,统计时只需统计一侧的点数就可以了。 类型: 扫描线划窗。 注意事项: 恶心的扫描线。。。 坑点: 总结: 划窗并不只在维护数列时用到。。。平面上的点也可以,这时一般需要先极角排序。 */