http://acm.hdu.edu.cn/showproblem.php?pid=4116
题意:给N个圆,求一条直线最多能经过几个圆?(相切也算)
思路:枚举中心圆,将其他圆的切线按照极角排序,并赋上权值(1\-1),那么我们for一遍,sum随时加上权值,当sum最大时,就可以更新答案。
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
const double eps=1e-;
const double Pi=acos(-);
int n;
struct Point{
double x,y,r;
Point(){}
Point(double x0,double y0,double r0):x(x0),y(y0),r(r0){}
Point(double x0,double y0):x(x0),y(y0){}
}p[];
bool vis[];
struct Line{
int id,c;
double ang;
Line(){}
Line(int id0,int c0,double ang0):id(id0),c(c0),ang(ang0){}
}L[];
int sgn(double x){
if (x>eps) return ;
if (x<-eps) return -;
return ;
}
double fix(double x){
while (sgn(x)<) x+=2.0*Pi;
while (sgn(x-Pi-Pi)>=) x-=2.0*Pi;
return x;
}
bool cmp(Line p1,Line p2){
int tmp=sgn(p1.ang-p2.ang);
if (tmp) return tmp<;
else return p1.c>p2.c;
}
int read(){
int t=,f=;char ch=getchar();
while (ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while (''<=ch&&ch<=''){t=t*+ch-'';ch=getchar();}
return t*f;
}
Point operator -(Point p1,Point p2){
return Point(p1.x-p2.x,p1.y-p2.y,);
}
double sqr(double x){
return x*x;
}
double dist(Point p){
return sqrt(sqr(p.x)+sqr(p.y));
}
double dist(Point p1,Point p2){
return dist(p1-p2);
}
Point getPoint(Point p,double ang){
return Point(p.x+cos(ang)*p.r,p.y+sin(ang)*p.r);
}
void cut_line(Point &A,Point &B,int &id,int &sum,int &len){
double dis=dist(A,B);
double Base=atan2(B.y-A.y,B.x-A.x);
if (sgn(A.r-B.r-dis)>) return;
if (sgn(B.r-A.r-dis)>=){
sum++;return;
}
double ang1=asin((B.r-A.r)/dis);
double ang2=asin((B.r+A.r)/dis);
if (sgn(A.r+B.r-dis)>=){
L[++len]=Line(id,,fix(Base-ang1));
L[++len]=Line(id,-,fix(Base+ang1+Pi));
return;
}
L[++len]=Line(id,,fix(Base-ang1));
L[++len]=Line(id,-,fix(Base+ang1+Pi));
L[++len]=Line(id,-,fix(Base+ang2));
L[++len]=Line(id,,fix(Base-ang2+Pi));
return;
}
int work(int n,int len){
int res=;
int sum=;
memset(vis,false,sizeof(bool)*(n+));
for (int i=;i<=(len<<);i++){
int k=(i>len)?i-len:i;
int id=L[k].id;
int c=L[k].c;
if (c==){
if (!vis[id]){
vis[id]=true;
sum++;
}
}else{
if (vis[id]){
vis[id]=false;
sum--;
}
}
if (sum>res) res=sum;
}
return res;
}
int main(){
int T=read(),Tcase=;
while (T--){
n=read();printf("Case #%d: ",++Tcase);
for (int i=;i<=n;i++)
scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].r);
int ans=;
for (int i=;i<=n;i++){
int len=;int sum=;
for (int j=;j<=n;j++) if (i!=j)
cut_line(p[i],p[j],j,sum,len);
std::sort(L+,L++len,cmp);
sum+=work(n,len);
ans=std::max(ans,sum);
}
printf("%d\n",ans);
}
return ;
}