题意

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

点数<=2000,坐标的绝对值和半径<=5000.

注意这里的连线指的是直线而不是线段.保证所有点都在圆外(不会落在圆的边界上).保证任意两个点的连线不会与圆相切.

分析

半年前写过题解.bzoj3663&&bzoj4660 Crazy Rabbit

因为最近联考考了这道题,然后发现我当时的题解写得一塌糊涂...于是重写一遍,顺便给当时看过我的题解的朋友道歉.

(捂脸熊.jpg)

首先对于圆外的点A,我们可以过它作两条圆的切线,找出两个切点之间的圆弧,这代表着从A放一个点光源时光线能照到的圆上的区间(也就是从点A能够"看到"的一段圆弧).我们可以用原点到切点的向量的极角来表示区间的端点.比如从点(0,sqrt(2))向半径为1的单位圆引切线,对应的区间就是[pi/4,3*pi/4].

关于"从某个点能够看到的一段圆弧",我们有一个至关重要的性质:

两个点所连的直线和圆没有交点,当且仅当这两个点分别"看到"的两端圆弧有公共部分但并不相互包含.

为了理解这个性质,可以自己在纸上画个圆,观察以下3条性质.

  1. 如果两个点"看到"的圆弧没有公共部分,那么它们之间连一条线段会和圆相交.
  2. 如果两个点"看到"的圆弧完全相互包含,那么它们之间连一条直线会和圆相交.
  3. 如果两个点"看到"的圆弧不满足(1)(2),那么它们之间连一条直线不和圆相交.

    这里本来想画个圆,不过比较懒就没有画

求出"看见"的区间只需要用基本的计算几何和一些三角函数.这一部分细节见代码.

那么问题至此转化为:在圆上选出一些区间使得它们两两有公共部分且不能相互包含.

我们发现,两个区间是否"有公共部分且不相互包含"只与这区间的端点有关,与区间代表的是端点划分出的优弧还是劣弧无关.

上一句话可能比较难理解.我画画图.

为了看起来方便,我们把圆周画得比较有宽度,把一些区间画在圆周内侧和外侧,实际上这些区间都是放在没有宽度的圆周上.

上面的红色区间和绿色区间满足"相交且不包含",但是红色区间和紫色区间也满足,绿色区间和蓝色区间也满足,蓝色区间和紫色区间也满足.

也就是说:我们随便把一些区间变成每个区间在圆上对应的互补区间,"相交且不包含"的关系是不变的.

如果这个结论比较难理解,可以考虑我们是怎样判断两个区间是否"相交且不包含".因为任意两点连线和圆不相切所以不会出现区间端点相同的情况.那么第一个区间的两个端点中必然一个被第二个区间包含,一个不被第二个区间包含.显然,这里我们把哪一个区间变成其在圆上的互补区间都不会对答案有任何影响.

这个性质的用处在于把环上的问题变成链上的问题.我们随便找一个点,从那个地方把圆断开为链(方便起见不如取x轴负半轴和圆的交点).如果有的区间跨过来这个断点,只需把那个区间变成它在圆上的互补区间.

现在问题转化为直线上有一些区间,选出尽量多的区间使得它们两两之间"相交但不包含"

考虑选出来的任意两个区间[l1,r1],[l2,r2],假如l1<l2,那么由于"相交且不包含"的限制,必然有r1<r2.也就是说,把所有的区间按照左端点排序之后,选出来的区间一定是右端点递增的.因此我们naive地猜想,答案是不是对所有区间按照左端点排个序,再按照排序之后的顺序把右端点拿出来跑LIS呢?通过看数据范围我们发现不是这样.因为这样选出来的一些区间虽然满足不会相互包含,却不一定满足两两有公共部分.考虑最终方案中选出来的所有区间中左端点最小的一个,因为区间两两之间有公共部分所以这个区间内必须包含其他所有区间的左端点.那么我们枚举这个左端点最小的区间,只把其他区间中左端点在这个区间内的区间拿出来,按左端点排序后对右端点跑LIS,就可以保证选出来的区间有公共部分而且不包含.复杂度为O(n^2logn).

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1505;
const double pi=acos(-1);
const double eps=1e-10;
int cmp(double x){
return x<-eps?-1:x>eps;
}
struct point{
double x,y;
point(){}
point(double a,double b){
x=a;y=b;
}
void read(){
scanf("%lf%lf",&x,&y);
}
}P[maxn]; int n,r;
double L[maxn],R[maxn],ori[maxn];
double dot(const point &A,const point &B){
return A.x*B.x+A.y*B.y;
}
point operator -(const point &A,const point &B){
return point(A.x-B.x,A.y-B.y);
}
double length(const point &A){
return sqrt(dot(A,A));
}
double arg(double x,double y){
return atan2(y,x);
}//the angle of vector(x,y),from(-pi,pi] ,arg(-1,0)=pi,arg(1,0)=0 arg(0,1)=pi/2
int tot,seq[maxn];
bool inside(double l,double r,double x){
if(l<r){
return cmp(l-x)*cmp(r-x)==-1;
}else{
return cmp(l-x)*cmp(r-x)==1;
}
}
bool inter(int i,int j){
return inside(L[i],R[i],L[j])^inside(L[i],R[i],R[j]);
}
bool cmp1(const int &a,const int &b){
return cmp(L[a]-L[b])==-1;
}
double m[maxn];
double v[maxn];
int f[maxn];
int binary(double x){
int l=0,r=tot;
while(l<=r){
int mid=(l+r)>>1;
if(m[mid]<x)l=mid+1;
else r=mid-1;
}
return l-1;
}
int lis(){
for(int i=0;i<=tot;++i)m[i]=1e10;
m[0]=-1e10;
for(int i=1;i<=tot;++i)v[i]=R[seq[i]];
int ans=0;
for(int i=1;i<=tot;++i){
f[i]=binary(v[i])+1;
if(f[i]>ans)ans=f[i];
if(v[i]<m[f[i]])m[f[i]]=v[i];
}
return ans;
}
int main(){
int tests;scanf("%d",&tests);
while(tests--){
scanf("%d%d",&n,&r);
for(int i=1;i<=n;++i)P[i].read();
for(int i=1;i<=n;++i)ori[i]=arg(P[i].x,P[i].y);
for(int i=1;i<=n;++i){
double dlt=acos(r/length(P[i]));
L[i]=ori[i]-dlt;R[i]=ori[i]+dlt;
if(L[i]<-pi)L[i]+=2*pi;
if(R[i]>pi)R[i]-=2*pi;
if(L[i]>R[i])swap(L[i],R[i]);
}
// for(int i=1;i<=n;++i)printf("%.3f %.3f\n",L[i],R[i]);
int ans=0;
for(int i=1;i<=n;++i){
//enum start point
tot=0;
for(int j=1;j<=n;++j){
if(j==i)continue;
if(cmp(L[i]-L[j])==-1&&inter(i,j)){
seq[++tot]=j;
}
}
sort(seq+1,seq+tot+1,cmp1);
int tmp=lis()+1;
if(tmp>ans)ans=tmp;
}
printf("%d\n",ans);
}
return 0;
}

bzoj3663/4660CrazyRabbit && bzoj4206最大团的更多相关文章

  1. 三倍经验——bzoj3663、4660、4206 Crazy Rabbit/最大团

    题目描述: 3663 4660 4206 题解: 第一眼:不成立的互相连边,然后用网络流求解无向图最小点覆盖! 好吧我不会. 正解: 每个点对应圆上的一段圆弧,长这样: 设对应圆弧$(l,r)$. 若 ...

  2. 代码的坏味道(5)——数据泥团(Data Clumps)

    坏味道--数据泥团(Data Clumps) 特征 有时,代码的不同部分包含相同的变量组(例如用于连接到数据库的参数).这些绑在一起出现的数据应该拥有自己的对象. 问题原因 通常,数据泥团的出现时因为 ...

  3. 软件海贼团 OnePiece (版权所有)

    最近迷上了“海贼王”这部动画片,不仅仅是因为其中的人物个个性格鲜明,剧情跌宕起伏扣人心弦,各种耍宝搞笑,还感觉到这个团队很像理想中的敏捷软件团队. 作为一直带团队的我,感觉“海贼王”这个动画片给了我很 ...

  4. Golang友团无闻Go语言Web基础视频教程

    教程内容:GO语言资料Golang友团无闻Go语言编程基础Golang友团无闻Go语言Web基础教程 Go语言Web基础教程列表:[Go Web基础]12Go Web 扩展学习.mp4[Go Web基 ...

  5. 【深度分享】千团大战:看今天商业WiFi乱局及其破解之道

    不知道还有没有人记得起始于2010年的千团大战.从2010年初开始,第一家团购网站上线以来,到2011年底,团购网站的数量超过了5000家.当时就有很多媒体预言,2013年,团购的泡沫就将褪去,将有9 ...

  6. 猿团YTFCloud生态系统,全面服务创业者

    9月15日,YTFCloud已正式开启了内测. 创业者翘首以待的YTFCloud,虽然让部分创业者感受到了它的神奇,但对于更多暂时无法尝试的创业者来说,它依然有一层神秘的面纱. 今天小编就来带你近距离 ...

  7. 猿团YTFCloud--5分钟自制APP,开发从未如此简单

    9月15日,YTFCloud将正式开启内测, 这意味着猿团YTF框架产品线全面升级.同时,公测过后,YTFCloud的APP线上DIY服务将面向所有用户,让人人都能成为APP“开发商”. 什么是YTF ...

  8. zoj1492 最大团

    Maximum Clique Time Limit: 10 Seconds      Memory Limit: 32768 KB Given a graph G(V, E), a clique is ...

  9. ecshop 团购点击价格变动

    前提:价格阶梯只能设置一级 需要用到: jquery,transport.js(transport_jquery.js),Ajax.call html页面 js代码,还需要插入jquery,trans ...

随机推荐

  1. 20155322 2017-2018-1 《信息安全系统设计》第五周 MyBash实现

    #20155322 2017-2018-1<信息安全系统设计>第五周 MyBash实现 [博客目录] 实现要求 相关知识 bash fork exec wait 相关问题 fork返回两次 ...

  2. [BZOJ2961]共点圆-[凸包+cdq分治]

    Description 传送门 Solution 考虑对于每一个点: 设圆的坐标为(x,y),点的坐标为(x0,y0).依题意得,当一个点在圆里,需要满足(x-x0)2+(y-y0)2<=x2+ ...

  3. 【LG3206】[HNOI2010]城市建设

    [LG3206][HNOI2010]城市建设 题面 洛谷 题解 有一种又好想.码得又舒服的做法叫线段树分治+\(LCT\) 但是因为常数过大,无法跑过此题. 所以这里主要介绍另外一种玄学\(cdq\) ...

  4. 【Unity3d】MenuItem修饰的方法无法触发的可能原因

    遇到了MenuItem修饰的方法无法触发的情况,顺利解决. 类放在Editor目录下,该类下其他方法被MenuItem修饰可以触发. 后来发现我修饰的方法和该类下另一个方法重名了. 改方法名,问题解决 ...

  5. Appium+python 自动发送邮件(2)(转)

    (原文:https://www.cnblogs.com/fancy0158/p/10056418.html) 移动端执行完测试case之后,通过邮件自动发送测试报告.大体流程如下: 1.通过unitt ...

  6. katalon系列十六:代码运行时实时创建元素对象或列表

    Katalon的常规方法是先抓取元素并保存到仓库,在脚本中需要用到的时候调取,但假如元素属性和个数是可变的,就不能事先保存到仓库了,需要在脚本运行时实时创建. 代码运行时实时创建一个元素对象的例子im ...

  7. CentOS 下 Java 的下载、安装、配置

    CentOS 下 Java 的下载.安装.配置 系统: CentOS 7 x86_64 Java 版本: 1.8.0_171 本文将 Java 目录放在 /usr/local/java 文件夹下,读者 ...

  8. tensorflow中tensor与数组之间的转换

    # 主要是两个方法: # 1.数组转tensor:数组a, tensor_a=tf.convert_to_tensor(a) # 2.tensor转数组:tensor b, array_b=b.eva ...

  9. 【UGUI】 (一)------- 放大镜

    在许多游戏或应用中,我们常常看到放大镜的身影,而在Unity里面,制作一个简易的放大镜是非常简单的.    一. 创建一个3DObject 创建一个Cube或者 Cylinder,这里为了更像放大镜一 ...

  10. JavaScript里的循环方法之forEach,for-in,for-of

    JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML(标 ...