uva1606

题意:平面上有n个点,每个点都是黑点或者是白点,现在需要防止一条隔板,使得隔板一侧的白点数加上另一侧的黑点数总数最大,隔板上的点可以看做是在任意一侧;

分析:

  可以先枚举一个基准点,然后将一条直线绕着这个点旋转,每当直线扫过一个点就可以动态维护,每个点最多被扫描到两次


在这里我们使用atan2和叉积,用叉积来判断两条直线的角度,用atan2来算极角



代码如下:

#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
using namespace std;

#define me(s)  memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;

const int N=1000+5;

struct Point
{
    int x,y;
    double rad;
    bool operator<(const Point&rhs)const
    {
        return rad<rhs.rad;
    }
}op[N],p[N];

int n,color[N];

bool Left(Point A,Point B)
{
    return A.x*B.y-A.y*B.x>=0;
}

int solve()
{
    if(n<=2)return 2;
    int ans=0;

    for(int i=0;i<n;i++)  //枚举基准点op[i]
    {
        int k=0;
        for(int j=0;j<n;j++)
            if(j!=i)
        {
            p[k].x=op[j].x-op[i].x;  //将其他点都转换为相对坐标
            p[k].y=op[j].y-op[i].y;
            if(color[j]){p[k].x=-p[k].x;p[k].y=-p[k].y;} //如果是黑点,将它绕原点旋转180度即可看做白点处理了
            p[k].rad=atan2(p[k].y,p[k].x);
            k++;
        }
        sort(p,p+k);

        int L=0,R=0,cnt=2;  //分隔线上有2个点
        while(L<k)  //O-p[L]作为分隔线,O-p[R]作为扫描线,注意,R一直是在0~k-1之间不停地循环着,直到L>=k才停止
        {
            if(R==L){R=(R+1)%k;cnt++;}  //空区域,暂时多计入一个点,最后舍去
            while(R!=L&&Left(p[L],p[R])) //扫描线一直逆时针旋转,直到旋转角度刚刚>180度停止统计
            {
                R=(R+1)%k;
                cnt++;
            }
            cnt--; //舍去多计入的点,也可以理解为由于分隔线的旋转,原来在分隔线上的点现在变为了右侧的点,要减掉一个
            L++;   //分隔线旋转
            ans=max(ans,cnt); //统计这一轮扫描的结果
        }
    }
    return ans;
}

int main()
{
    while(~scanf("%d",&n)&&n)
    {
        rep(i,n)
        scanf("%d%d%d",&op[i].x,&op[i].y,&color[i]);
        printf("%d\n",solve());
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值