Computational Geometry val.2

Computational Geometry val.2

Pre Cheese: convex hull and Basic Operation

This paper stuck write rotation, cross half-plane, the smallest circle overlay content is to be noted

Geometry unit structure board

Incomplete(I know

struct point{
    double x,y;
    point(double x=0,double y=0): x(x),y(y){} //构造函数,非常方便
    double operator*(point b){ //叉积 
        return x*b.y-y*b.x;
    }
    double operator^(point b){ //点积 
        return x*b.x+y*b.y;
    }
    point operator-(point b){
        return point(x-b.x,y-b.y);
    } 
    point operator+(point b){
        return point(x+b.x,y+b.y);
    }//向量运算
    point operator*(double b){ //数乘 
        return point(x*b,y*b);
    }
    db dis(){ //模长
        return sqrt(x*x+y*y);
    }
}b[N];
int comp0(double x){
    return fabs(x)<=eps?0:(x>0?1:-1);
}//判0,防止精度误差
struct line{
    point p,v;//p起点,v终点 ,表示线段
    double theta;
    bool operator <(line y){
        return comp0(theta-y.theta)==0?comp0((y.v-p)*(v-p))<0:comp0(theta-y.theta)<0;
    }//排序,保证第一关键字是极角,第二关键字是与右边的距离(用叉积判相对关系,在左边的放后面) 
};
point inter(line a,line b){//交点  intersection 
    point v1=a.v-a.p,v2=b.v-b.p;
    return b.p+v2*(((b.p-a.p)*v1)/(v1*v2));
}//此处默认了没有平行的情况 , 判断线段有没有交点就是判断点是否在线段上,但是半平面交是直线(只是用线段表示)

Rotating stuck

\ [\ Large {\ text {↗ spin transfer ↘↗ card ↘↗ housing (ko↗)}} \]
Yes, very true

This algorithm is used to find convex polygons diameter

Basic concepts

  1. Tangent

    A line through the vertex, the polygon are on one side of this line

  2. On the heel point

    Two points on the polygon to make a pair of parallel lines, polygons whole between two lines

Seeking

Consider counterclockwise enumeration of each side and locate the edge furthest from this point, then this point diameter and a vertex of this edge is composed of possible answers

weSurprisinglyFound that the order of appearance of the point is counterclockwise, then you can \ (O (n) \) to obtain the

(Of course, also required convex hull \ (n \ log n \)

NOTE: If required a separate an edge furthest point you can find third (unimodal function)

template

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define db double
using namespace std;
struct point{
    double x,y;
    point(double x=0,double y=0): x(x),y(y){}
    double operator*(point b){
        return x*b.y-y*b.x;
    }
    point operator-(point b){
        return point(x-b.x,y-b.y);
    } 
    point operator+(point b){
        return point(x+b.x,y+b.y);
    }
    db dis(){
        return sqrt(x*x+y*y);
    }
}; 
const int N = 50021;
point p[N],h[N];
int tp=0,stk[N],usd[N];
int cmp(point a,point b){
    return a.x==b.x?a.y<b.y:a.x<b.x;
}
int n=0;
db Fabs(db a){
    return a>0?a:-a;
}
db disl(point a,point b,point x){
    return Fabs((a-x)*(b-x)/(a-b).dis());
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lf%lf",&p[i].x,&p[i].y);
    }
    sort(p+1,p+n+1,cmp);
    stk[++tp]=1;
    for(int i=2;i<=n;i++){
        while(tp>1&&(p[stk[tp]]-p[stk[tp-1]])*(p[i]-p[stk[tp]])<=0) usd[stk[tp--]]=0;
        usd[i]=1;stk[++tp]=i;
    }
    int ntp=tp;
    for(int i=n-1;i>=1;i--){
        if(!usd[i]){
            while(tp>ntp&&(p[stk[tp]]-p[stk[tp-1]])*(p[i]-p[stk[tp]])<=0) usd[stk[tp--]]=0; 
            usd[i]=1;stk[++tp]=i;           
        }
    }
    for(int i=1;i<=tp;i++){
        h[i]=p[stk[i]];
    }
    if(tp<=2){ //只有一个点 
        puts("0");
        return 0;
    }
    if(tp==3){  
        printf("%.0lf\n",(h[1]-h[2]).dis()*(h[1]-h[2]).dis());
        return 0;
    }
    db ans=0;
    int t=1;
    //注意最后一个点(就是1号点)要保留,因为后面有h[i+1],[t+1],方便操作 
    for(int i=1;i<tp;i++){
        while(disl(h[i],h[i+1],h[t])<disl(h[i],h[i+1],h[t+1])) t=t%(tp-1)+1; //逆时针枚举点  
        ans=max(ans,max((h[i]-h[t]).dis(),(h[i+1]-h[t]).dis())); //两端点到此点 
    } 
    printf("%.0f",ans*ans);
    return 0;
}

Half plane cross

Here we use half-plane vector representations to the left or right half plane

Front cheese: cross the line

Drawing it, with similar results
\ [h_1 = \ frac {fabs ((v_2-p_1) * (p_2-p_1))} {dis (v_2-p_2)}, h_2 = \ frac {fabs ((v_2-v_1) * (p_2-v_1))} {dis (v_2-p_2)} \]

\[ line(p_1,v_1) \cap line(p_2,v_2)=p_1+(v_1-p_1)*\frac{h_1}{h_1+h_2} \]

S & I algorithm

Sort polar angle

So that \ (\ Theta = arctan \ FRAC YX \) , with its small to large order to obtain a new set of vectors

Algorithmic process

  1. Counterclockwise direction is positive, building side (line)

  2. The segment of the polar angle ordering

  3. Removing same polar angle in the case, the position of the right side (the left-half plane if required post (counterclockwise convex polygon) words)

  4. With a double-ended set of queue storage segment \ (L \) , traversing all segments

  5. Analyzing Effect of a half-plane of the line segment was added after post, (head and tail of the deque judgment, because the line segment are added orderly, means influence the intersection of this line on the other side (undesired side before the intersection)), that is, whether the right side in the sub-line
  6. Back then delete must first delete the tail head, see the specific wjyyy big brother blog, will be attached later

  7. Analyzing the influence last formed loop (tail head once again updated, update the tail head once again)

  8. The last remaining segment collection \ (L \) , even if the final half-plane cross required
  9. It can be used throughout the cross product direction sentence

template

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define db double
const double eps=1e-9;
using namespace std;
const int N = 10001;
struct point{
    double x,y;
    point(double x=0,double y=0): x(x),y(y){}
    double operator*(point b){ //叉积 
        return x*b.y-y*b.x;
    }
    double operator^(point b){ //点积 
        return x*b.x+y*b.y;
    }
    point operator-(point b){
        return point(x-b.x,y-b.y);
    } 
    point operator+(point b){
        return point(x+b.x,y+b.y);
    }
    point operator*(double b){ //数乘 
        return point(x*b,y*b);
    }
    db dis(){ //模长
        return sqrt(x*x+y*y);
    }
}b[N];
int comp0(double x){
    return fabs(x)<=eps?0:(x>0?1:-1);
}
struct line{
    point p,v;//p起点,v终点 ,表示线段 
    double theta;
    bool operator <(line y){
        return comp0(theta-y.theta)==0?comp0((y.v-p)*(v-p))<0:comp0(theta-y.theta)<0;
    }//排序,保证第一关键字是极角,第二关键字是与右边的距离(用叉积判相对关系,在左边的放后面) 
};
point inter(line a,line b){//交点  intersection 
    point v1=a.v-a.p,v2=b.v-b.p;
    return b.p+v2*(((b.p-a.p)*v1)/(v1*v2));
}//此处默认了没有平行的情况 , 判断线段有没有交点就是判断点是否在线段上,但是半平面交是直线(只是用线段表示)
int out(line a,line b,line k){
    point ins=inter(a,b); //此处要判断的是ins是否在k的右边,画个图 
    return comp0((k.v-k.p)*(ins-k.p))<0;
} 
int n;
line a[N],q[N];int top;
void work(){
    sort(a+1,a+top+1);
    int cnt=0;
    for(int i=1;i<=top;i++){
        if(comp0(a[i].theta-a[i-1].theta)!=0) cnt++;
        a[cnt]=a[i];//极角相同时,右边的更优(排序保证了在左边) 
    }
    int h=1,t=0;
    q[++t]=a[1],q[++t]=a[2];//既然是交,至少包含两个元素
    for(int i=3;i<=cnt;i++){
        while(h<t&&out(q[t-1],q[t],a[i])) t--; //踢掉一些点 ,注意一定要先踢后面,不然会有些错 
        while(h<t&&out(q[h+1],q[h],a[i])) h++;
        q[++t]=a[i];
    }  
    while(h<t&&out(q[t-1],q[t],q[h])) t--; //由于是环形,判断影响
    while(h<t&&out(q[h+1],q[h],q[t])) h++;
    q[t+1]=q[h];
    top=0;
    for(int i=h;i<=t;i++){
        b[++top]=inter(q[i],q[i+1]); 
    } 
} 
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int k;scanf("%d",&k);
        for(int j=1;j<=k;j++){
            scanf("%lf%lf",&b[j].x,&b[j].y);
        } 
        b[k+1]=b[1];
        for(int j=1;j<=k;j++){
            a[++top].p=b[j];a[top].v=b[j+1];//逆时针给出,如果不知道的话可以叉积判断 
        }
    }
    for(int i=1;i<=top;i++){
        a[i].theta=atan2(a[i].v.y-a[i].p.y,a[i].v.x-a[i].p.x);
    } 
    work();
    double ans=0;
    if(top<=2){
        printf("%.3lf",0.0);return 0;//二 边 形 
    }
    b[top+1]=b[1]; //同样,环形处理方法 
    for(int i=1;i<=top;i++){
        ans+=(b[i]*b[i+1]); 
    }
    ans/=2.0;
    if(comp0(ans)==0) printf("%.3lf",0.0);
    else{
        printf("%.3lf",fabs(ans));
    }
    return 0;
}

Minimum round coverage

Random incremental method

Random incremental method

Consider Imperial \ (i, j \) constant in a circle, \ (J <I \)

For \ (\ FORALL K <J \) , configured to reaching the \ (i, j, k \ ) round

If the current \ (K \) in the inner circle, is calculated \ (k + 1 \)

Otherwise update \ (i, j, k \ ) circumscribed circle (three points determine a circle)

For the previous two, if at some point within the circle, skip

Otherwise enumeration \ (J \ in [1, i) \) , recalculate

time complexity

Appears to be three-cycle ah QwQ, the more points within the circle can not optimize how much of it?

But we are beginning \ (\ text {random_suffle} \ ) for a moment, then turned into a complexity at the desired sense

So how much is it? Men and women silent tears, it reached a staggering \ (O (the n-) \) !

analysis:

  1. For over \ (P_i, P_j \) of the circle, each point of the cycle at least once, for the \ (O (j) \)
  2. For over \ (P_i \) circle, consider front cover \ (I \) circle point is determined by three points, then the previous \ (i-1 \) point, it is desirable there are two points calculated the next level
  3. For the smallest circle to cover all the points, there are expected to contribute three points
  4. 总复杂度:\(O\left(\sum_{i=1}^{n} \frac{3}{i} \sum_{j=1}^{i} \frac{2}{j} \cdot j\right)=O(6\cdot n)=O(n)\)

template

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define db double
#include<cstdlib>
#include<ctime>
const double eps=1e-17;
using namespace std;
const int N = 100001;
struct point{
    double x,y;
    point(double x=0,double y=0): x(x),y(y){}
    double operator*(point b){ //叉积 
        return x*b.y-y*b.x;
    }
    double operator^(point b){ //点积 
        return x*b.x+y*b.y;
    }
    point operator-(point b){
        return point(x-b.x,y-b.y);
    } 
    point operator+(point b){
        return point(x+b.x,y+b.y);
    }
    point operator*(double b){ //数乘 
        return point(x*b,y*b);
    }
    db dis(){ //模长
        return sqrt(x*x+y*y);
    }
}p[N];
int comp0(double x){
    return fabs(x)<=eps?0:(x>0?1:-1);
}
struct line{
    point p,v;//p起点,v终点 ,表示线段 
    line(point a,point b): p(a),v(b){}
    double theta;
    bool operator <(line y){
        return comp0(theta-y.theta)==0?comp0((y.v-p)*(v-p))<0:comp0(theta-y.theta)<0;
    }//排序,保证第一关键字是极角,第二关键字是与右边的距离(用叉积判相对关系,在左边的放后面) 
};
point inter(line a,line b){//交点  intersection 
    point v1=a.v-a.p,v2=b.v-b.p;
    return b.p+v2*(((b.p-a.p)*v1)/(v1*v2));
}//此处默认了没有平行的情况 , 判断线段有没有交点就是判断点是否在线段上,但是半平面交是直线(只是用线段表示)
int out(line a,line b,line k){
    point ins=inter(a,b); //此处要判断的是ins是否在k的右边,画个图 
    return comp0((k.v-k.p)*(ins-k.p))<0;
} 
int n;
int in(point k,point c,double r){
    return comp0(r-(k-c).dis())>=0;
}
point chrt(point a){
    return point(-a.y,a.x);
} 
void randomShuffle(){
    srand(19260817+time(0)); //知道为什么不用STL的吗? 
    for (int i=1;i<=n;i++){
        int j=(rand()%n+1926)%n+1;//这里随便rand()%n就行了,但我们要把玄学发扬光大【滑稽】
        swap(p[i],p[j]);
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lf%lf",&p[i].x,&p[i].y);
    }
    randomShuffle(); //这句很重要
    point c;
    db r=0.0;
    for(int i=1;i<=n;i++){
        if(in(p[i],c,r)) continue;
        c=p[i],r=0;//重新计算
        for(int j=1;j<i;++j){
            if(in(p[j],c,r)) continue;
            r=(p[j]-p[i]).dis()/2.0;
            c=p[i]*0.5+p[j]*0.5;
            for(int k=1;k<j;k++){
                if(in(p[k],c,r)) continue;
                line a=line((p[i]+p[j])*0.5,chrt(p[i]-p[j])+(p[i]+p[j])*0.5);
                line b=line((p[k]+p[j])*0.5,chrt(p[j]-p[k])+(p[j]+p[k])*0.5);
                c=inter(a,b);r=(c-p[i]).dis();
            }
        }
    }
    printf("%.10f\n%.10f %.10f",r,c.x,c.y);
    return 0;
}

postscript

I look at this DALAO the blog to learn

It should also val.3(Learning nekopara

To write about definite integral base / Minkowski and / Simpson integration (adaptive Simpson) Han

Guess you like

Origin www.cnblogs.com/lcyfrog/p/11695145.html