枚舉每個點做旋轉點,按照極角排序,掃描一次,得出結果.
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#define PI 3.14159265359#define eps 1e-8using 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;}