如果,没有紫书上的翻译的话,我觉得我可能读不懂这道题。=_=||
题意:
平面上有n个点,不是白点就是黑点。现在要放一条直线,使得直线一侧的白点与另一侧的黑点加起来数目最多。直线上的点可以看作位于直线的任意一侧。
分析:
首先假设直线经过两个点,否则可以移动直线使其经过两个点,并且总数不会减少。
所以,我们可以先枚举一个基点,然后以这个点为中心。
围绕基点将其他点按照极角排序,将直线旋转,统计符合要求的点的个数。
小技巧:
如果将所有的黑点以基点为中心做一个中心对称,则符合要求的点的个数就变成了直线一侧的点的个数。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1000 + 10; 6 7 int n, color[maxn]; 8 9 struct Point 10 { 11 int x, y; 12 Point(int x=0, int y=0):x(x), y(y) {} 13 double rad; 14 bool operator < (const Point& rhs) const 15 { return rad < rhs.rad; } 16 }op[maxn], p[maxn]; 17 18 Point operator - (const Point& A, const Point& B) 19 { return Point(A.x-B.x, A.y-B.y); } 20 21 int Cross(const Point& A, const Point& B) 22 { return A.x*B.y - A.y*B.x; } 23 24 int solve() 25 { 26 //if(n <= 3) return n; 27 int ans = 0; 28 for(int i = 0; i < n; ++i) 29 {//枚举基点 30 int k = 0; 31 for(int j = 0; j < n; ++j) if(i != j) 32 { 33 p[k] = op[j] - op[i]; 34 if(color[j]) { p[k].x = -p[k].x; p[k].y = -p[k].y; }//将黑点做个中心对称 35 p[k].rad = atan2(p[k].y, p[k].x); 36 k++; 37 } 38 sort(p, p+k); 39 40 int L = 0, R = 0, cnt = 2; 41 for(; L < k; ++L) 42 {//统计p[L]到p[R]之间的点 43 if(L == R) { R = (R+1)%k; cnt++; } 44 while(L != R && Cross(p[L], p[R]) >= 0) { R = (R+1)%k; cnt++; }//当区间大于180度停止 45 cnt--; 46 ans = max(ans, cnt); 47 } 48 } 49 return ans; 50 } 51 52 int main() 53 { 54 freopen("in.txt", "r", stdin); 55 56 while(scanf("%d", &n) == 1 && n) 57 { 58 for(int i = 0; i < n; ++i) scanf("%d%d%d", &op[i].x, &op[i].y, &color[i]); 59 printf("%d ", solve()); 60 } 61 62 return 0; 63 }