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-9; const double Pi=acos(-1); 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[800005]; bool vis[800005]; struct Line{ int id,c; double ang; Line(){} Line(int id0,int c0,double ang0):id(id0),c(c0),ang(ang0){} }L[800005]; int sgn(double x){ if (x>eps) return 1; if (x<-eps) return -1; return 0; } double fix(double x){ while (sgn(x)<0) x+=2.0*Pi; while (sgn(x-Pi-Pi)>=0) x-=2.0*Pi; return x; } bool cmp(Line p1,Line p2){ int tmp=sgn(p1.ang-p2.ang); if (tmp) return tmp<0; else return p1.c>p2.c; } int read(){ int t=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } Point operator -(Point p1,Point p2){ return Point(p1.x-p2.x,p1.y-p2.y,0); } 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)>0) return; if (sgn(B.r-A.r-dis)>=0){ 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)>=0){ L[++len]=Line(id,1,fix(Base-ang1)); L[++len]=Line(id,-1,fix(Base+ang1+Pi)); return; } L[++len]=Line(id,1,fix(Base-ang1)); L[++len]=Line(id,-1,fix(Base+ang1+Pi)); L[++len]=Line(id,-1,fix(Base+ang2)); L[++len]=Line(id,1,fix(Base-ang2+Pi)); return; } int work(int n,int len){ int res=0; int sum=0; memset(vis,false,sizeof(bool)*(n+4)); for (int i=1;i<=(len<<1);i++){ int k=(i>len)?i-len:i; int id=L[k].id; int c=L[k].c; if (c==1){ 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=0; while (T--){ n=read();printf("Case #%d: ",++Tcase); for (int i=1;i<=n;i++) scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].r); int ans=0; for (int i=1;i<=n;i++){ int len=0;int sum=1; for (int j=1;j<=n;j++) if (i!=j) cut_line(p[i],p[j],j,sum,len); std::sort(L+1,L+1+len,cmp); sum+=work(n,len); ans=std::max(ans,sum); } printf("%d ",ans); } return 0; }