zoukankan      html  css  js  c++  java
  • HDU 6617 Enveloping Convex(凸包+半平面交+二分)

    首先对于这m个点维护出一个凸包M,那么问题就变成了判断凸包P进行放大缩小能不能包含凸包M。(凸包P可以进行中心对称变换再进行放大缩小,见题意)

    如何判断合适的相似比呢,我们可以用二分去放大缩小凸包P的坐标,得到最小的相似比。

    接下来就是如何判断是否包含。我们需要对凸包P上的每一条向量,在凸包M上找到这么一个点,使得这个点左侧的所有凸包M上的点都在向量的左侧,那么我们可以直接同时逆时针枚举,用一个变量维护凸包M上的点,因为是同逆时针,凸包M上的点至少有一个只会被遍历一次,那么复杂度可以证明为On,这样就可以维护出来凸包P上的向量所对应的在凸包M上的点。因为包含关系,满足所有的向量的对应点都应该在向量的左侧,那么我们将这个向量相对于这个点的坐标求出来,然后维护一个半平面交是否有解即可,判断这个半平面交维护出来的是否是一个合法的凸包,当然由于我们是逆时针枚举的向量,需要先对凸包P进行逆时针转动,所以我们没必要将这些相对于坐标的向量排序,直接维护半平面交,但是最后我们需要判断维护出来的凸包是否严格按照逆时针旋转,因为位置是相对的,可能出现一个向下的向量的左侧是一个向上的向量,这样的关系是矛盾的。

    注意细节,由于我的模板用的是求直线交点,精度比较差,eps开的比较小。

      1 //        ——By DD_BOND
      2 
      3 //#include<bits/stdc++.h>
      4 //#include<unordered_map>
      5 //#include<unordered_set>
      6 #include<functional>
      7 #include<algorithm>
      8 #include<iostream>
      9 //#include<ext/rope>
     10 #include<iomanip>
     11 #include<climits>
     12 #include<cstring>
     13 #include<cstdlib>
     14 #include<cstddef>
     15 #include<cstdio>
     16 #include<memory>
     17 #include<vector>
     18 #include<cctype>
     19 #include<string>
     20 #include<cmath>
     21 #include<queue>
     22 #include<deque>
     23 #include<ctime>
     24 #include<stack>
     25 #include<map>
     26 #include<set>
     27 
     28 #define fi first
     29 #define se second
     30 #define MP make_pair
     31 #define pb push_back
     32 
     33 #pragma GCC optimize(3)
     34 #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
     35 
     36 typedef long long ll;
     37 
     38 using namespace std;
     39 
     40 const int MAXN=1e5+10;
     41 const double eps=1e-18;
     42 const double pi=acos(-1.0);
     43 const ll INF=0x3f3f3f3f3f3f3f3f;
     44 
     45 inline int dcmp(double x){
     46     if(fabs(x)<eps)    return 0;
     47     return (x>0? 1: -1);
     48 }
     49 
     50 inline double sqr(double x){ return x*x; }
     51 
     52 struct Point{
     53     double x,y;
     54     Point(){ x=0,y=0; }
     55     Point(double _x,double _y):x(_x),y(_y){}
     56     void input(){ scanf("%lf%lf",&x,&y); }
     57     void output(){ printf("%.2f %.2f
    ",x,y); }
     58     bool operator <(const Point &b)const{
     59         return (dcmp(x-b.x)==0? dcmp(y-b.y)<0 : x<b.x);
     60     }
     61     double operator ^(const Point &b)const{        //叉积
     62         return x*b.y-y*b.x;
     63     }
     64     double operator *(const Point &b)const{        //点积
     65         return x*b.x+y*b.y;
     66     }
     67     bool operator ==(const Point &b)const{
     68         return dcmp(x-b.x)==0&&dcmp(y-b.y)==0;
     69     }
     70     Point operator +(const Point &b)const{
     71         return Point(x+b.x,y+b.y);
     72     }
     73     Point operator -(const Point &b)const{
     74         return Point(x-b.x,y-b.y);
     75     }
     76     Point operator *(double a){
     77         return Point(x*a,y*a);
     78     }
     79     Point operator /(double a){
     80         return Point(x/a,y/a);
     81     }
     82     double len2(){    //长度平方
     83         return sqr(x)+sqr(y);
     84     }
     85     double len(){   //长度
     86         return sqrt(len2());
     87     }
     88 };
     89 
     90 inline double cross(Point a,Point b){    //叉积
     91     return a.x*b.y-a.y*b.x;
     92 }
     93 
     94 inline double dot(Point a,Point b){    //点积
     95     return a.x*b.x+a.y*b.y;
     96 }
     97 
     98 struct Line{
     99     Point s,e;
    100     Line(){}
    101     Line(Point _s,Point _e):s(_s),e(_e){}
    102     Point operator &(const Line &b)const{     //求两直线交点
    103         Point res=s;
    104         double t=((s-b.s)^(b.s-b.e))/(((s-e)^(b.s-b.e))+eps);
    105         res.x+=(e.x-s.x)*t;
    106         res.y+=(e.y-s.y)*t;
    107         return res;
    108     }
    109 };
    110 
    111 int relation(Point p,Line l){    //点和向量关系   1:左侧   2:右侧   3:在线上
    112     int c=dcmp(cross(p-l.s,l.e-l.s));
    113     if(c<0)    return 1;
    114     else if(c>0)    return 2;
    115     else    return 3;
    116 }
    117 
    118 bool counter_wise(Point *p,int n){            //多边形点集调整为逆时针顺序
    119     for(int i=1;i<n-1;i++)
    120         if(dcmp(cross(p[i]-p[i-1],p[i+1]-p[i-1]))>0)    return 0;
    121         else if(dcmp(cross(p[i]-p[i-1],p[i+1]-p[i-1]))<0){
    122             reverse(p,p+n);
    123             return 1;
    124         }
    125     return 1;
    126 }
    127 
    128 Point tmp[MAXN];
    129 int convex_hull(Point *p,int n,Point *ch){    //求凸包
    130     int m=0;
    131     sort(p,p+n);
    132     for(int i=0;i<n;i++){
    133         while(m>1&&dcmp(cross(tmp[m-1]-tmp[m-2],p[i]-tmp[m-1]))<=0)    m--;
    134         tmp[m++]=p[i];
    135     }
    136     int k=m;
    137     for(int i=n-2;i>=0;i--){
    138         while(m>k&&dcmp(cross(tmp[m-1]-tmp[m-2],p[i]-tmp[m-1]))<=0)    m--;
    139         tmp[m++]=p[i];
    140     }
    141     if(n>1)    m--;
    142     for(int i=0;i<m;i++)    ch[i]=tmp[i];
    143     return m;
    144 }
    145 
    146 Line que[MAXN];
    147 int half_plane_intersection(Line *L,int n){    //以逆时针方向 半平面交求多边形的核  ch表示凸包的顶点  返回顶点数 -1则表示不存在
    148     int head=0,tail=1;
    149     que[0]=L[0],que[1]=L[1];
    150     for(int i=2;i<n;i++){
    151         while(tail>head&&relation(que[tail]&que[tail-1],L[i])==2)   tail--;
    152         while(tail>head&&relation(que[head]&que[head+1],L[i])==2)   head++;
    153         que[++tail]=L[i];
    154     }
    155     while(tail>head&&relation(que[tail]&que[tail-1],que[head])==2)  tail--;
    156     while(tail>head&&relation(que[head]&que[head+1],que[tail])==2)  head++;
    157     for(int i=head;i<=tail;i++){
    158         int j=(i==tail? head: i+1);
    159         if(dcmp(cross(que[i].e-que[i].s,que[j].e-que[j].s))<=0)
    160             return 0;
    161     }
    162     return 1;
    163 }
    164 
    165 Line line[MAXN];
    166 Point p[MAXN],q[MAXN],ops[MAXN];
    167 
    168 int main(void){
    169     int T;  scanf("%d",&T);
    170     while(T--){
    171         int n;  scanf("%d",&n);
    172         for(int i=0;i<n;i++)    p[i].input();
    173         int m;  scanf("%d",&m);
    174         for(int i=0;i<m;i++)    q[i].input();
    175         counter_wise(p,n);  m=convex_hull(q,m,q);
    176         double ans=INF;
    177         for(int t=1;t<=2;t++){
    178             for(int i=0;i<n;i++)    p[i]=Point(-p[i].x,-p[i].y);
    179             for(int i=0,j=0;i<n;i++){
    180                 while(dcmp(cross(p[(i+1)%n]-p[i],q[(j-1+m)%m]-q[j]))<0||dcmp(cross(p[(i+1)%n]-p[i],q[(j+1)%m]-q[j]))<0)   j=(j+1)%m;
    181                 ops[i]=q[j];
    182             }
    183             double l=0,r=1e10;
    184             for(int i=0;i<70;i++){
    185                 double mid=(l+r)/2;
    186                 for(int j=0;j<n;j++)    line[j]=Line(p[j]*mid-ops[j],p[(j+1)%n]*mid-ops[j]);
    187                 if(half_plane_intersection(line,n)) r=mid;
    188                 else    l=mid;
    189             }
    190             ans=min(ans,l);
    191         }
    192         printf("%.10lf
    ",ans);
    193     }
    194     return 0;
    195 }
  • 相关阅读:
    02、书店寻宝(一)
    01、博客爬虫
    00、下载文件
    068、Calico的网络结构是什么?(2019-04-11 周四)
    067、如何部署Calico网络 (2019-04-10 周三)
    066、Weave如何与外网通信?(2019-04-09 周二)
    065、容器在Weave中如何通信和隔离?(2019-04-08 周一)
    064、Weave网络结构分析(2019-04-04 周四)
    063、如何使用weave网络(2019-04-03 周三)
    CMD运行指令
  • 原文地址:https://www.cnblogs.com/dd-bond/p/11308219.html
Copyright © 2011-2022 走看看