uva1606 Amphiphilic Carbon Molecules 极角排序+扫描线划窗

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1<<29;
const double EPS=1e-10;
const double Pi=acos(-1.0);

struct Point
{
    int x,y,c;
    double rad;
    friend bool operator<(Point A,Point B)
    {
        return A.rad<B.rad;
    }
    friend Point operator-(Point A,Point B)
    {
        return {A.x-B.x,A.y-B.y};
    }
    void debug()
    {
        printf("x=%2d y=%2d c=%d\n",x,y,c);
    }
};Point p[maxn],t[maxn];
int n;

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

int solve(int k)
{
    if(n<=2) return n;
    int cnt=0;
    REP(i,1,n){
        if(i!=k){
            t[cnt]=p[i]-p[k];
            t[cnt].c=p[i].c;
            if(t[cnt].c){
                t[cnt].x=-t[cnt].x;
                t[cnt].y=-t[cnt].y;
            }
            t[cnt].rad=atan2(t[cnt].y*1.0,t[cnt].x*1.0);
            cnt++;
        }
    }
    int res=1;
    sort(t,t+cnt);
    for(int L=0,R=0,tmp=2;L<cnt;L++){
        if(L==R) R=(R+1)%cnt,tmp++;
        while(L!=R&&Left(t[L],t[R])) R=(R+1)%cnt,tmp++;
        tmp--;
        res=max(res,tmp);
    }
    return res;
}

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>n,n){
        REP(i,1,n) scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].c);
        int ans=0;
        REP(i,1,n) ans=max(solve(i),ans);
        cout<<ans<<endl;
    }
    return 0;
}

/**
题意:
    平面上有n个点,每个点为白点或黑点,放置一隔板,使一侧的白点数+另一侧的黑点数最大。
    隔板上的点可视为任意一侧。
分析:
    由于最优时,隔板一定经过至少两个点,所以枚举基准点,然后再枚举隔板上的另一点确定隔板方向,
    极角排序后进行划窗统计。复杂度n^2*logn。
    这里有个技巧,确定基准点后,可以将所有的黑点关于基准点中心对称到另一侧,统计时只需统计一侧的点数就可以了。
类型:
    扫描线划窗。
注意事项:
    恶心的扫描线。。。
坑点:
总结:
    划窗并不只在维护数列时用到。。。平面上的点也可以,这时一般需要先极角排序。
*/
View Code

 

posted @ 2015-12-08 14:58  __560  阅读(301)  评论(0编辑  收藏  举报