fzu1873 Coin Puzzle

题意:在一个凸多边形内放置,两个圆,这两个圆不能重叠,给你凸包上的点和两个圆的半径,问能不能放置

旋转卡壳求 两个凸多边形 的最远点对

#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\n",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");
        }
    }
}

 

posted on 2015-08-12 13:58  天凉了  阅读(260)  评论(0编辑  收藏  举报

导航