题意:在一个凸多边形内放置,两个圆,这两个圆不能重叠,给你凸包上的点和两个圆的半径,问能不能放置
旋转卡壳求 两个凸多边形 的最远点对
#include<iostream> #include<vector> #include<cstring> #include<cstdio> #include<cmath> #include<stdlib.h> #include<queue> #include<map> #include<algorithm> using namespace std; const double eps = 1e-8; const double pi = acos(-1.0); const double INF = 1e9; const int mmax=1000; double sqr(double x){ return x*x; } int cmp(double x){ if(fabs(x)<eps) return 0; if(x>0) return 1; return -1; } struct point{ double x,y; int index; point(){} point(double a,double b):x(a),y(b){} void input(){ scanf("%lf%lf",&x,&y); } friend point operator + (const point &a,const point &b){ return point(a.x+b.x,a.y+b.y); } friend point operator - (const point &a,const point &b){ return point(a.x-b.x,a.y-b.y); } friend bool operator == (const point &a,const point &b){ return (cmp(a.x-b.x)==0)&&(cmp(a.y-b.y))==0; } friend point operator * (const point &a,double b){ return point(a.x*b,a.y*b); } friend point operator / (const point &a,double b){ return point(a.x/b,a.y/b); } friend double operator ^ (const point &a,const point &b) { return a.x*b.y - a.y*b.x; } double operator *(const point &b)const { return x*b.x + y*b.y; } double norm(){ //向量的模长 return sqrt(sqr(x)+sqr(y)); } }; double det(const point &a,const point &b){ //向量的叉集 return a.x*b.y-a.y*b.x; } double dot(const point &a,const point &b){ //向量的点集 return a.x*b.x+a.y*b.y; } double dot(const point &a,const point &b,const point &c){ //向量的点集ba 到bc return dot(a-b,c-b); } double dist(const point &a,const point &b){ //两点间的距离 return (a-b).norm(); } point rotate_point(const point &p,double A){ // 绕原点逆时针旋转 A(弧度) double tx=p.x,ty=p.y; return point(tx*cos(A)-ty*sin(A),tx*sin(A)+ty*cos(A)); } double xml(point x,point t1,point t2){ // 如果值为正,(t1-x)在(t2-x)的瞬时间方向 return det((t1-x),(t2-x)); } double area(point x,point y,point z){ return (det(y-x,z-x)); } struct line { point a,b; line(){} line(point x,point y):a(x),b(y){} }; point P_chuizhi_line(point a,point l1,point l2) // 求一个点,使得ac垂直于l1l2 { point c; l2.x -= l1.x; l2.y -= l1.y; c.x = a.x - l1.x - l2.y + l1.x; c.y = a.y - l1.y + l2.x + l1.y; return c; } point P_To_seg(point P,line L) //点到线段 最近的一个点 { point result; double t = ((P-L.a)*(L.b-L.a))/((L.b-L.a)*(L.b-L.a)); if(t >= 0 && t <= 1) { result.x = L.a.x + (L.b.x - L.a.x)*t; result.y = L.a.y + (L.b.y - L.a.y)*t; } else { if(dist(P,L.a) < dist(P,L.b)) result = L.a; else result = L.b; } return result; } double dis_p_to_line(point p,line l){ //点到直线的距离 return fabs(area(p,l.a,l.b))/dist(l.a,l.b); } double dis_p_to_seg(point p,line l) //点到线段的距离 { return dist(p,P_To_seg(p,l)); } double dis_pall_seg(point p1, point p2, point p3, point p4) //平行线段之间的最短距离 { return min(min(dis_p_to_seg(p1,line(p3,p4)), dis_p_to_seg(p2, line(p3, p4))), min(dis_p_to_seg(p3,line(p1, p2)), dis_p_to_seg(p4,line(p1, p2))) ); } bool intbr(line l1,line l2) { // 线段相交 return max(l1.a.x,l1.b.x) >= min(l2.a.x,l2.b.x) && max(l2.a.x,l2.b.x) >= min(l1.a.x,l1.b.x) && max(l1.a.y,l1.b.y) >= min(l2.a.y,l2.b.y) && max(l2.a.y,l2.b.y) >= min(l1.a.y,l1.b.y) && cmp((l2.a-l1.a)^(l1.b-l1.a))*cmp((l2.b-l1.a)^(l1.b-l1.a)) <= 0 && cmp((l1.a-l2.a)^(l2.b-l2.a))*cmp((l1.b-l2.a)^(l2.b-l2.a)) <= 0; } point line_inter(point A,point B,point C,point D){ //直线相交交点 point ans; double a1=A.y-B.y; double b1=B.x-A.x; double c1=A.x*B.y-B.x*A.y; double a2=C.y-D.y; double b2=D.x-C.x; double c2=C.x*D.y-D.x*C.y; ans.x=(b1*c2-b2*c1)/(a1*b2-a2*b1); ans.y=(a2*c1-a1*c2)/(a1*b2-a2*b1); return ans; } int n,m; point ttmp; point pt1[mmax],pt2[mmax]; bool cmpx(point xx,point yy){ if(cmp(xx.y-yy.y)==0) return xx.x<yy.x; return xx.y<yy.y; } bool cmpd(point xx, point yy){ double db=(xx-ttmp)^(yy-ttmp); if(cmp(db)==0) return dist(xx,ttmp)<dist(yy,ttmp); if(cmp(db)>0) return 1; else return 0; } point grp1[mmax],grp2[mmax]; int Graham(point* grp,point *pt,int n){ //凸包 int top=1; sort(pt,pt+n,cmpx);ttmp=pt[0]; sort(pt+1,pt+n,cmpd); grp[0]=pt[0]; grp[1]=pt[1]; for(int i=2;i<n;i++){ while(top>0){ double db=(pt[i]-grp[top])^(grp[top]-grp[top-1]); if(cmp(db)>=0) top--; else break; } grp[++top]=pt[i]; } return top+1; } double rotating_calipers(point* grp ,int len){ //旋转卡壳求最远点对 int i=0,j=1; double ans=0; point pansx=grp[0],pansy=grp[0]; grp[len]=grp[0]; while(i<len){ while(area(grp[i],grp[i+1],grp[j+1])> area(grp[i],grp[i+1],grp[j])) j=(j+1)%len; if(dist(grp[i],grp[j])>dist(pansx,pansy)){ pansx=grp[i]; pansy=grp[j]; } i++; } ans=dist(pansx,pansy); // printf("%.1f ",ans); return ans+eps; } double rotating_calipers2(point* grp1,int len1,point* grp2,int len2){ //旋转卡壳 求两个凸包的最近距离 int p=0,q=0; for(int i=0;i<len1;i++) if(grp1[i].y<grp1[p].y) p=i; for(int i=0;i<len2;i++) if(grp2[i].y>grp2[q].y) q=i; double ans=1e99,tmp; grp1[len1]=grp1[0];//避免取模 grp2[len2]=grp2[0];//避免取模 for(int i=0;i<len1;i++){ while(tmp=cmp(area(grp1[p],grp1[p+1],grp2[q+1])- area(grp1[p],grp1[p+1],grp2[q]))>0) q=(q+1)%len2; if(tmp==0) ans=min(ans,dis_pall_seg(grp1[p],grp1[p+1],grp2[q],grp2[q+1])); else ans=min(ans,dis_p_to_seg(grp2[q],line(grp1[p],grp1[p+1]))); p=(p+1)%len1; } return ans; } double rotating_calipers3(point* grp ,int len){ //旋转卡壳求凸包宽度 int p=0,q=0; int tmp; for(int i=0;i<len;i++) if(grp[i].y<grp[p].y) p=i; for(int j=0;j<len;j++) if(grp[j].y>grp[q].y) q=j; double ans=1e30; for(int i=0;i<len;i++){ while(tmp=cmp(area(grp[p],grp[p+1],grp[(q+1)%len])- area(grp[p],grp[p+1],grp[q]))>0) q=(q+1)%len; ans=min(ans,dis_p_to_line(grp[q],line(grp[p],grp[(p+1)%len]))); p=(p+1)%len; } return ans; } double rotating_calipers4(point* grp,int len){ double ans; int xmin=0,xmax=0,ymin=0,ymax=0; for(int i=0;i<len;i++) if(cmp(grp[xmin].x-grp[i].x)>0) xmin=i; for(int i=0;i<len;i++) if(cmp(grp[xmax].x-grp[i].x)<0) xmax=i; for(int i=0;i<len;i++) if(cmp(grp[ymin].y-grp[i].y)>0) ymin=i; for(int i=0;i<len;i++) if(cmp(grp[ymax].y-grp[i].y)<0) ymax=i; ans=(grp[ymax].y-grp[ymin].y)*(grp[xmax].x-grp[xmin].x); grp[len]=grp[0]; for(int i=0;i<len;i++){ while(cmp(area(grp[ymin],grp[ymin+1],grp[ymax+1])- area(grp[ymin],grp[ymin+1],grp[ymax]))>=0) ymax=(ymax+1)%len; while(cmp(dot(grp[xmax+1],grp[ymin],grp[ymin+1])- dot(grp[xmax],grp[ymin],grp[ymin+1]))>=0) xmax=(xmax+1)%len; if(i==0) xmin=xmax; while(cmp(dot(grp[xmin+1],grp[ymin+1],grp[ymin])- dot(grp[xmin],grp[ymin+1],grp[ymin]))>=0) xmin=(xmin+1)%len; double L1=dis_p_to_line(grp[ymax],line(grp[ymin],grp[ymin+1])); point a=P_chuizhi_line(grp[xmin],grp[ymin],grp[ymin+1]); double L2=dis_p_to_line(grp[xmax],line(grp[xmin],a)); if(ans>L1*L2){ ans=L1*L2; } ymin=(ymin+1)%len; } return ans; } struct seg{ point s,e; double angle; void get_angle(){angle=atan2(e.y-s.y,e.x-s.x);} }; point get_inter(seg a,seg b){ double u=xml(a.s,a.e,b.s),v=xml(a.e,a.s,b.e); point t; t.x=(b.s.x*v+b.e.x*u)/(u+v); t.y=(b.s.y*v+b.e.y*u)/(u+v); return t; } //半平面相交 seg l1[mmax],l2[mmax],dq[mmax]; int Lcnt,Lcnt2; double r1,r2; bool segcmp(seg a,seg b){ if(cmp(a.angle-b.angle)!=0) return a.angle<b.angle; return cmp(xml(a.s,b.s,b.e))>0; } double area_tp(seg* l1,int len){ double s=0; int num=0; l1[len]=l1[0]; for(int i=0;i<len;i++) pt2[num++]=get_inter(l1[i],l1[i+1]); for(int i=1;i<len-1;i++) s+=xml(pt2[0],pt2[i],pt2[i+1]); return s/2; } int HalfPlaneIntersect(seg* l1,int len,seg* ll,int kind){ sort(l1,l1+len,segcmp); int cnt=1; for(int i=1;i<len;i++) if(cmp(l1[i].angle-l1[cnt-1].angle)!=0) l1[cnt++]=l1[i]; len=cnt; dq[0]=l1[0]; dq[1]=l1[1]; int head=0,tail=1; for(int i=2;i<len;i++){ while(head<tail&&xml(l1[i].s,l1[i].e,get_inter(dq[tail],dq[tail-1]))<0) tail--; while(head<tail&&xml(l1[i].s,l1[i].e,get_inter(dq[head],dq[head+1]))<0) head++; dq[++tail]=l1[i]; } while(head<tail&&xml(dq[head].s,dq[head].e,get_inter(dq[tail],dq[tail-1]))<0) tail--; while(head<tail&&xml(dq[tail].s,dq[tail].e,get_inter(dq[head],dq[head+1]))<0) head++; int num=0; double ans=0; dq[tail+1]=dq[head]; for(int i=head;i<=tail;i++) ll[num++]=dq[i]; if(kind==0){ if(num<3) return 0; return num; } else{ int lt=0; for(int i=head;i<=tail;i++){ pt2[lt++]=get_inter(dq[i],dq[i+1]); } double sum=0; pt2[lt]=pt2[0]; for(int i=0;i<lt;i++) sum+=xml(point(0,0),pt2[i],pt2[i+1]); if(cmp(sum)!=0) return 1; else return 0; } } void changePolygon(seg* l,double h,int ln) { double len, dx, dy; for (int i = 0; i < ln; i++) { len = dist(l[i].s, l[i].e); dx = (l[i].s.y - l[i].e.y) / len * h; dy = (l[i].e.x - l[i].s.x) / len * h; l1[i].s.x = l[i].s.x + dx; l1[i].s.y = l[i].s.y + dy; l1[i].e.x = l[i].e.x + dx; l1[i].e.y = l[i].e.y + dy; l1[i].angle = l[i].angle; } } int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } double rotating_ok(point* grp1,int len1,point* grp2,int len2){ //旋转卡壳 求两个凸包的最远距离 int p=0,q=0; for(int i=0;i<len1;i++) if(grp1[i].y<grp1[p].y) p=i; for(int i=0;i<len2;i++) if(grp2[i].y>grp2[q].y) q=i; double ans=0,tmp; grp1[len1]=grp1[0];//避免取模 grp2[len2]=grp2[0];//避免取模 for(int i=0;i<len1;i++){ while(tmp=cmp(area(grp1[p],grp1[p+1],grp2[q+1])- area(grp1[p],grp1[p+1],grp2[q]))>0) q=(q+1)%len2; ans=max(ans,dist(grp1[p],grp2[q])); p=(p+1)%len1; } return ans; } int main(){ #ifndef ONLINE_JUDGE freopen("input.txt","r",stdin); #endif // ONLINE_JUDGE int cas=0; seg l3[mmax],l4[mmax]; while(cin>>n>>r1>>r2){ if(r1>r2) swap(r1,r2); for(int i=0;i<n;i++) pt1[i].input(); pt1[n]=pt1[0]; Lcnt=0; for(int i=0;i<n;i++) { l2[Lcnt].s=pt1[i]; l2[Lcnt].e=pt1[i+1]; l2[Lcnt++].get_angle(); } printf("Case %d: ",++cas); changePolygon(l2,r1,Lcnt); int len3=HalfPlaneIntersect(l1,Lcnt,l3,0); changePolygon(l2,r2,Lcnt); int len4=HalfPlaneIntersect(l1,Lcnt,l4,0); if(len3==0||len4==0) puts("No"); else{ Lcnt=0; l3[len3]=l3[0]; l4[len4]=l4[0]; int cnt1=0,cnt2=0; for(int i=0;i<len3;i++) pt1[cnt1++]=get_inter(l3[i],l3[i+1]); for(int j=0;j<len4;j++) pt2[cnt2++]=get_inter(l4[j],l4[j+1]); if(rotating_ok(pt1,cnt1,pt2,cnt2)>=r1+r2) puts("Yes"); else puts("No"); } } }