zoukankan      html  css  js  c++  java
  • BZOJ 4206: 最大团

    4206: 最大团

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 91  Solved: 36
    [Submit][Status][Discuss]

    Description

    给出平面上N个点的坐标,和一个半径为R的圆心在原点的圆。对于两个点,它们之间有连边,当且仅当它们的连线与圆不相交。
    求此图的最大团。

    Input

    第一行两个整数N和R, 表示点数和圆的半径。
    接下来N 行,每行两个整数xi 和yi,表示第i个点的坐标
    保证每个点都严格在园外,且两两直线不与圆相切。

    Output

    输出一个整数:最大团的大小。

    Sample Input

    6 3
    0 6
    -7 -4
    -3 -2
    7 -5
    -2 3
    8 -3

    Sample Output

    4

    HINT

    对于100%的数据,1≤N≤2000,|xi|,|yi|,R≤5000

    Source

    分析:

    考虑什么样子的两个点确定的直线是合法的...

    我们从每个点向圆做两条切线...这两条切线之间有一段弧...如果两个点确定的直线可以选择,当且仅当这两个点对应的弧相交并且不包含...

    现在我们把圆切开展成一条线段,我们把弧覆盖这个切点的点的弧取反...并不会影响答案...

    现在我们得到了若干区间,我们要找的是包含区间最多的合法序列使得其满足:

    $l_1<l_2<l_3<......<l_n<r_1<r_2<r_3<......<r_n$

    现在我们枚举第一个区间是什么,这样我们就确定了可选的$l_i$的范围,我们把可选的区间提取出来,按照$l$排序,然后求$r$的最长上升子序列就好了...

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    //by NeighThorn
    using namespace std;
     
    const int maxn=2000+5;
    const double pi=acos(-1.0),inf=1e8;
     
    int n,ans,cas;
    double r,tmp[maxn],posx[maxn],posy[maxn];
     
    struct M{
         
        double x,y;
        int del;
         
        inline void init(void){
            del=0;
        }
         
        friend bool operator < (M a,M b){
            if(a.del!=b.del) return a.del<b.del;
            if(a.x!=b.x) return a.x<b.x;
            if(a.y!=b.y) return a.y<b.y;
        }
         
    }no[maxn];
     
    signed main(void){
        scanf("%d%lf",&n,&r);
        for(int i=1;i<=n;i++)
            scanf("%lf%lf",&posx[i],&posy[i]),no[i].init();
        for(int i=1,x,y;i<=n;i++){
            double len=sqrt(posx[i]*posx[i]+posy[i]*posy[i]);
            if(len<=r){
                no[i].del=1;break;
            }
            double ang1=atan2(posy[i],posx[i]),ang2=acos(r/len);
            no[i].x=ang1-ang2;no[i].y=ang1+ang2;
            if(no[i].y>pi) no[i].y-=2*pi,swap(no[i].x,no[i].y);
            if(no[i].x<-pi) no[i].x+=2*pi,swap(no[i].x,no[i].y);
        }
        sort(no+1,no+n+1);ans=0;
        while(no[n].del==1) n--;
        for(int i=1;i<=n;i++){
            double x=no[i].x,y=no[i].y;
            for(int j=0;j<n;j++) tmp[j]=inf;
            for(int j=i+1;j<=n&&no[j].x<y;j++){
                if(no[j].y>no[i].y)
                    *lower_bound(tmp,tmp+n,no[j].y)=no[j].y;
            }
            ans=max(ans,(int)(lower_bound(tmp,tmp+n,inf)-tmp)+1);
        }
        printf("%d
    ",ans);
        return 0;
    }
    

      


    By NeighThorn

  • 相关阅读:
    django第二个项目使用模板做一个站点访问计数器
    python 从ftp下载数据
    django第一个项目HelloWord
    数据挖掘之KNN分类
    java的函数参数传递
    将数组按照奇偶顺序排列
    win7 64位下安装nltk的问题
    [转]安装androidADT插件长时间停留在calculating requirements and dependencies
    排序算法之插入排序
    非等值折半查找
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6694342.html
Copyright © 2011-2022 走看看