UVa 1606 - Amphiphilic Carbon Molecules

链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4481

 

题意:

平面上有n(n≤1000)个点,每个点为白点或者黑点。现在需放置一条隔板,
使得隔板一侧的白点数加上另一侧的黑点数总数最大。隔板上的点可以看作是在任意一侧。

 

分析:

扫描法
不妨假设隔板一定经过至少两个点(否则可以移动隔板使其经过两个点,并且总数不会变小),
可以先枚举一个基准点,然后将一条直线绕这个点旋转。每当直线扫过一个点,就可以动态修改两侧的点数。
注意本题存在多点共线的情况,如果用反三角函数计算极角,然后判断极角是否相同的话,很容易产生精度误差。
应该把极角相等的条件进行化简,只使用整数运算进行判断。

 

代码:

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int UP = 1000 + 5;
 7 
 8 struct DOT {
 9     int x, y;
10     double rad;
11     bool operator < (const DOT& that) const {
12         return rad < that.rad;
13     }
14 } dot[UP];
15 
16 int n, X[UP], Y[UP], C[UP];
17 
18 inline bool left(DOT& a, DOT& b){ //判断点a是否在参考原点b的左侧
19     return a.y * b.x >= a.x * b.y;
20 }
21 
22 int solve(){
23     if(n < 4) return n;
24     int ans = 0;
25     for(int i = 0; i < n; i++){ //枚举原点
26         int k = 0;
27         for(int t = 0; t < n; t++){
28             if(t == i) continue;
29             dot[k].x = X[t] - X[i]; //将点i视为原点,对其他点的坐标进行转换
30             dot[k].y = Y[t] - Y[i];
31             if(C[t]){ //如果点t是黑点,那么将其变为相对于原点对称的白点,这样结果不变
32                 dot[k].x = -dot[k].x;
33                 dot[k].y = -dot[k].y;
34             }
35             dot[k].rad = atan2(dot[k].y, dot[k].x); //求出O-dot[k]与正x轴的夹角的弧度值
36             k++;
37         }
38         sort(dot, dot + k);
39         int R = 0, sum = 2; //一开始分隔线上有两个点
40         for(int L = 0; L < k; L++){ //枚举分隔线的另一个点,即以O-dot[L]为分隔线
41             if(R == L){ //为了不与下面的 R != L 发生冲突,将R点左移一位
42                 R = (R + 1) % k;
43                 sum++; //一开始也可抵消下面的 sum-- 的效果
44             }
45             while(R != L && left(dot[R], dot[L])){ //维护在分隔线左侧的点的个数
46                 R = (R + 1) % k;
47                 sum++;
48             }
49             sum--; //因为上一次分隔线的左移,上一个dot[L]变成了现在分隔线右侧的点,故总点数减1
50             ans = max(ans, sum);
51         }
52     }
53     return ans;
54 }
55 
56 int main(){
57     while(scanf("%d", &n) && n){
58         for(int i = 0; i < n; i++) scanf("%d%d%d", &X[i], &Y[i], &C[i]);
59         printf("%d\n", solve());
60     }
61     return 0;
62 }

 

posted @ 2017-12-22 03:25  Ctfes  阅读(178)  评论(0编辑  收藏  举报