完全不会计算几何。。。不过这题虽然是查别人的题解的,但是还是值得写一下题解来进一步解释一下。
思路是枚举一个基准点,将基准点到所有其他的点的向量按照极角排序,然后依次将每一个向量作为一种放置方法(下面把这个取出来作为基准的向量叫做基准向量,ICPC放在与基准向量共线的直线上,从向量的方向看过去,向量所在直线的左侧溶解color为0的点)扫描这种放置方式下溶解的点的数目。这里有个非常巧妙的地方,将color为1的点放到关于基准点对称的位置上,那么我们扫描时只需要将扫描向量从基准向量开始旋转180°记录下所有扫描线经过的点即可。
同时,当基准向量旋转时,只需要从上次扫描向量停下来的地方开始扫描,同时减去基准向量转过的区域内包括的点即可(由于基准向量每次只移动一个点,所以每次移动基准向量时,点的数目要在原先的基础上减去1,当扫描向量与基准向量重合的时候(这种情况是存在的:当所有的点全都共线的时候以第一个点作为基准点,每次移动基准向量,扫描向量都是从与基准向量重合的位置开始扫描的。),可以视为是刚开始扫描,先加上一个点后在扫描完成后减去,以与之前的过程保持一致)
AC代码如下:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
struct point
{
int x,y;
double rad;
point(int xx=0,int yy=0,double r=0.0):x(xx),y(yy),rad(r){}
bool operator< (const point &a)const
{
return rad<a.rad;
}
};
point p[10005],v[10005];
int color[10005];
bool left(point a,point b)
{
return a.x*b.y-a.y*b.x>=0;
}
int main(int argc, char const *argv[])
{
int n;
while(scanf("%d", &n)&&n!=0)
{
for(int i=0;i<n;i++)
{
scanf("%d %d %d", &p[i].x,&p[i].y, &color[i]);
}
int ans=0;
for(int i=0;i<n;i++)
{
int k=0;
for(int j=0;j<n;j++)
{
if(j!=i)
{
v[k].x=p[j].x-p[i].x;
v[k].y=p[j].y-p[i].y;
if(color[j])
{
v[k].x=-v[k].x;
v[k].y=-v[k].y;
}
v[k].rad=atan2((double)v[k].y,(double)v[k].x);
k++;
}
}
if(k<=2)
{
ans=n;
break;
}
sort(v,v+k);
int L=0,R=0,cnt=2;
for(L=0;L<k;L++)
{
if(L==R)
{
R=(R+1)%k;
cnt++;
}
while(L!=R&&left(v[L],v[R]))
{
R=(R+1)%k;
cnt++;
}
cnt--;
ans=max(ans,cnt);
}
}
printf("%d\n", ans);
}
return 0;
}