完全不會計算幾何。。。不過這題雖然是查別人的題解的,但是還是值得寫一下題解來進一步解釋一下。
思路是枚舉一個基準點,將基準點到所有其他的點的向量按照極角排序,然後依次將每一個向量作爲一種放置方法(下面把這個取出來作爲基準的向量叫做基準向量,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;
}