枚举每个点做旋转点,按照极角排序,扫描一次,得出结果.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define PI 3.14159265359
#define eps 1e-8
using namespace std;
struct Point
{
int x,y,r;
double ang;
} rem[1005],v[1005];
int n;
int cmp(const struct Point a,const struct Point b) //按角度排序(极角排序)
{
if (a.ang < b.ang)
return 1;
else return 0;
}
int sig(double a) //判断当前是否满足精度 0满足 1不满足 -1等于精度
{
if (fabs(a) < eps)
return 0;
else if (a > 0)
return 1;
else return -1;
}
int cross(struct Point a,struct Point b,struct Point c) //叉积
{
return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
}
int main()
{
while (scanf("%d",&n) && n)
{
int ans = 0;
for (int i = 1; i <= n; ++i)
{
scanf("%d%d%d",&v[i].x,&v[i].y, &v[i].r);
rem[i] = v[i]; //rem 存放最原始的数据
}
for (int i = 1; i <= n; ++i) //****枚举每个点做旋转点
{
for (int j = 1; j <= n; ++j) //对v赋值 对于属性是0的点,直接赋值,属性为1的点,对称赋值. 并计算角度
{
v[j] = rem[j];
if (v[j].r == 1) //如果是属性是1的点 对称到 直线的 另一端
{
v[j].x = rem[i].x * 2 - v[j].x;
v[j].y = rem[i].y * 2 - v[j].y;
}
v[j].ang = atan2(v[j].y - rem[i].y , v[j].x - rem[i].x); //计算弧度
}
swap(v[i],v[1]); //v[1]总是当前枚举的点 所以不断的交换v[i] 值与v[1]值
sort(v + 2, v + n + 1, cmp); //****极角排序
//开始点,已经有2个,v[1]和v[2] 然后对第三个点进行考虑
for(int s = 2,t = 3; s <= n && sig(v[s].ang) <= 0; s++) //****当前直线由v[1]和v[s]两点确定(选取直线,旋转扫描)
{
int on = 2; //on是直线上点的个数
for ( ; t <= n && cross(v[1],v[s],v[t]) >= 0; t++) //只判断一侧的点,t统计的是在一侧的点
{
if (cross(v[1],v[s],v[t]) == 0) //三点共线 在icpc线上
on++; //线上点+1
}
//t-s-1:0侧溶解0,1侧溶解0的情况能得到的值 n-(t-s+1)+on 0侧溶解1,1侧溶解0
ans = max(ans , max(t - s + 1, n - (t - s + 1) + on));
}
}
printf("%d\n",ans);
}
return 0;
}