zoukankan      html  css  js  c++  java
  • UVa 1606

    链接:

    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
    ", solve());
    60     }
    61     return 0;
    62 }
  • 相关阅读:
    打印乘法口诀
    sum() 求和用法
    Python 2 和 Python 3 有哪些主要区别
    列表 enumerat 解包, 针对索引和元素
    冒泡排序,纯数字列表排序 解包,加中间值
    python 字符串与列表的相互转换 数据类型转换
    赋值 深浅拷贝
    python去掉字符串中空格的方法
    #上节多线程内容回顾#多线程的使用场景 #多进程的基本使用
    #queue队列 #生产者消费者模型
  • 原文地址:https://www.cnblogs.com/hkxy125/p/8084014.html
Copyright © 2011-2022 走看看