zoukankan      html  css  js  c++  java
  • 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
    ",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");
            }
        }
    }
  • 相关阅读:
    *HDU 1392 计算几何
    *HDU 1115 计算几何
    *HDU 1086 计算几何
    *HDU 2108 计算几何
    HDU 1528 贪心模拟/二分图
    HDU 1281 二分图
    *HDU1150 二分图
    *HDU1151 二分图
    *HDU 1068 二分图
    *HDU 1054 二分图
  • 原文地址:https://www.cnblogs.com/ainixu1314/p/4724115.html
Copyright © 2011-2022 走看看