BZOJ 4206: 最大团 (关于圆的funny solution)


计算几何题,要么全场AK,要么全场骗分,那是因为当几何中各种精巧的转化与OI多变的解题方法融合在一起时,答案总是和乱搞很难区分。

这道题也算乱搞吧,这种题一般要枚举一个点,再继续分析,我们可以发现,做一个点关于圆的两条切线,在两条切线中间的点是不能选的。

然后是我的乱搞:

两条切线会将图分为3部分,一是枚举的点,二是切线左方的点,三是切线右方的点,

然后我认为左方的点和左方的点不会排斥,那么左边和右边成一个二分图,求一个最大独立集。

然而我错了。

正解:

两条切点之间的圆弧,可以发现,若两个点可以同时选,则两个圆弧的关系既不能是包含也不能是独立,得相交

所以把圆弧求出来,转化为最多选几条弧,每两条弧都相交且不包含。。。。。。

然后按左端点排序,求最长上升子序列:


ACcode:

#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<algorithm>
#define maxn 4005
#define PI 3.1415926535897932384626433832795
#define inf 0x3f3f3f3f
using namespace std;
 
int n;
double R;
double l[maxn],r[maxn];
 
double sqr(double a){
    return a*a;
}
 
struct Point{
    double x,y;
    Point(){}
    Point(double a,double b){x=a,y=b;}
    bool operator <(const Point nxt)const{
        return x<nxt.x;   
    }
     
    double operator *(const Point nxt)const{
        return sqrt(sqr(y-nxt.y)+sqr(x-nxt.x));
    } 
}P[maxn],O;
 
struct node{
	double l,r;
	bool operator <(const node nxt)const{
		return l<nxt.l;
	}
}s[maxn];

double Q[maxn];
int tp;

int main(){ 
	
	freopen("clique.in","r",stdin);
	freopen("clique.out","w",stdout);
     
    double sita,alph;
    scanf("%d%lf",&n,&R);
    for(int i=1;i<=n;i++){
        scanf("%lf%lf",&P[i].x,&P[i].y);
		if(P[i]*O<R){
			n--,i--;
			continue;
		}
        alph=atan2((P[i].y),(P[i].x));
        sita=acos((R)/(P[i]*O));
        s[i].l=alph-sita;
        s[i].r=alph+sita;
		if(s[i].r>PI) s[i].r-=2*PI,swap(s[i].l,s[i].r);
		if(s[i].l<-PI) s[i].l+=2*PI,swap(s[i].l,s[i].r);
    }
    
	sort(s+1,s+1+n);
	
	int ans=0;
    for(int i=1;i<=n;++i)
    {
        Q[tp=0]=s[i].r;tp++;
		for(int j=i+1;j<=n && s[j].l<Q[0]; j++)
			if(s[j].r>Q[tp-1]) Q[tp++]=s[j].r;
			else
				if(s[j].r>Q[0])
					*lower_bound(Q,Q+tp,s[j].r)=s[j].r;
		ans=max(ans,tp);
    }
	printf("%d",ans);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值