题意:平面上有n个点,每个点都是黑点或者是白点,现在需要防止一条隔板,使得隔板一侧的白点数加上另一侧的黑点数总数最大,隔板上的点可以看做是在任意一侧;
分析:
可以先枚举一个基准点,然后将一条直线绕着这个点旋转,每当直线扫过一个点就可以动态维护,每个点最多被扫描到两次
在这里我们使用atan2和叉积,用叉积来判断两条直线的角度,用atan2来算极角
代码如下:
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
using namespace std;
#define me(s) memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;
const int N=1000+5;
struct Point
{
int x,y;
double rad;
bool operator<(const Point&rhs)const
{
return rad<rhs.rad;
}
}op[N],p[N];
int n,color[N];
bool Left(Point A,Point B)
{
return A.x*B.y-A.y*B.x>=0;
}
int solve()
{
if(n<=2)return 2;
int ans=0;
for(int i=0;i<n;i++) //枚举基准点op[i]
{
int k=0;
for(int j=0;j<n;j++)
if(j!=i)
{
p[k].x=op[j].x-op[i].x; //将其他点都转换为相对坐标
p[k].y=op[j].y-op[i].y;
if(color[j]){p[k].x=-p[k].x;p[k].y=-p[k].y;} //如果是黑点,将它绕原点旋转180度即可看做白点处理了
p[k].rad=atan2(p[k].y,p[k].x);
k++;
}
sort(p,p+k);
int L=0,R=0,cnt=2; //分隔线上有2个点
while(L<k) //O-p[L]作为分隔线,O-p[R]作为扫描线,注意,R一直是在0~k-1之间不停地循环着,直到L>=k才停止
{
if(R==L){R=(R+1)%k;cnt++;} //空区域,暂时多计入一个点,最后舍去
while(R!=L&&Left(p[L],p[R])) //扫描线一直逆时针旋转,直到旋转角度刚刚>180度停止统计
{
R=(R+1)%k;
cnt++;
}
cnt--; //舍去多计入的点,也可以理解为由于分隔线的旋转,原来在分隔线上的点现在变为了右侧的点,要减掉一个
L++; //分隔线旋转
ans=max(ans,cnt); //统计这一轮扫描的结果
}
}
return ans;
}
int main()
{
while(~scanf("%d",&n)&&n)
{
rep(i,n)
scanf("%d%d%d",&op[i].x,&op[i].y,&color[i]);
printf("%d\n",solve());
}
}