[原创]计算几何个人模板

      都是自己整理的一些简单的计算几何模板,如果里面有问题请指出,毕竟我自己学的也不怎么好,由于计算几何部分东西很多,所以此文章不够全面,但是有新内容我会随时更新此文章的!

1.   前序

1. 注意舍入方式(0.5的舍入方向);防止输出-0.

2. 几何题注意多测试不对称数据.

3. 整数几何注意xmult和dmult是否会出界;

   符点几何注意eps的使用.

4. 避免使用斜率;注意除数是否会为0.

5. 公式一定要化简后再代入.

6. 判断同一个2*PI域内两角度差应该是

   abs(a1-a2)<beta||abs(a1-a2)>pi+pi-beta;

   相等应该是

   abs(a1-a2)<eps||abs(a1-a2)>pi+pi-eps;

7. 需要的话尽量使用atan2,注意:atan2(0,0)=0,

   atan2(1,0)=pi/2,atan2(-1,0)=-pi/2,atan2(0,1)=0,atan2(0,-1)=pi.

8. cross product = |u|*|v|*sin(a)

   dot product = |u|*|v|*cos(a)

9. (P1-P0)x(P2-P0)结果的意义:

   正: <P0,P1>在<P0,P2>顺时针(0,pi)内

   负: <P0,P1>在<P0,P2>逆时针(0,pi)内

   0 : <P0,P1>,<P0,P2>共线,夹角为0或pi

10. 误差限缺省使用1e-?

 

几何公式:

三角形:

1. 半周长 P=(a+b+c)/2

2. 面积 S=aHa/2=absin(C)/2=sqrt(P(P-a)(P-b)(P-c))

3. 中线 Ma=sqrt(2(b^2+c^2)-a^2)/2=sqrt(b^2+c^2+2bccos(A))/2

4. 角平分线 Ta=sqrt(bc((b+c)^2-a^2))/(b+c)=2bccos(A/2)/(b+c)

5. 高线 Ha=bsin(C)=csin(B)=sqrt(b^2-((a^2+b^2-c^2)/(2a))^2)

6. 内切圆半径 r=S/P=asin(B/2)sin(C/2)/sin((B+C)/2)

               =4Rsin(A/2)sin(B/2)sin(C/2)=sqrt((P-a)(P-b)(P-c)/P)

               =Ptan(A/2)tan(B/2)tan(C/2)

7. 外接圆半径 R=abc/(4S)=a/(2sin(A))=b/(2sin(B))=c/(2sin(C))

四边形:

D1,D2为对角线,M对角线中点连线,A为对角线夹角

1. a^2+b^2+c^2+d^2=D1^2+D2^2+4M^2

2. S=D1D2sin(A)/2

(以下对圆的内接四边形)

3. ac+bd=D1D2

4. S=sqrt((P-a)(P-b)(P-c)(P-d)),P为半周长

正n边形:

R为外接圆半径,r为内切圆半径

1. 中心角 A=2PI/n

2. 内角 C=(n-2)PI/n

3. 边长 a=2sqrt(R^2-r^2)=2Rsin(A/2)=2rtan(A/2)

4. 面积 S=nar/2=nr^2tan(A/2)=nR^2sin(A)/2=na^2/(4tan(A/2))

圆:

1. 弧长 l=rA

2. 弦长 a=2sqrt(2hr-h^2)=2rsin(A/2)

3. 弓形高 h=r-sqrt(r^2-a^2/4)=r(1-cos(A/2))=atan(A/4)/2

4. 扇形面积 S1=rl/2=r^2A/2

5. 弓形面积 S2=(rl-a(r-h))/2=r^2(A-sin(A))/2

棱柱:

1. 体积 V=Ah,A为底面积,h为高

2. 侧面积 S=lp,l为棱长,p为直截面周长

3. 全面积 T=S+2A

棱锥:

1. 体积 V=Ah/3,A为底面积,h为高

(以下对正棱锥)

2. 侧面积 S=lp/2,l为斜高,p为底面周长

3. 全面积 T=S+A

棱台:

1. 体积 V=(A1+A2+sqrt(A1A2))h/3,A1.A2为上下底面积,h为高

(以下为正棱台)

2. 侧面积 S=(p1+p2)l/2,p1.p2为上下底面周长,l为斜高

3. 全面积 T=S+A1+A2

圆柱:

1. 侧面积 S=2PIrh

2. 全面积 T=2PIr(h+r)

3. 体积 V=PIr^2h

圆锥:

1. 母线 l=sqrt(h^2+r^2)

2. 侧面积 S=PIrl

3. 全面积 T=PIr(l+r)

4. 体积 V=PIr^2h/3

圆台:

1. 母线 l=sqrt(h^2+(r1-r2)^2)

2. 侧面积 S=PI(r1+r2)l

3. 全面积 T=PIr1(l+r1)+PIr2(l+r2)

4. 体积 V=PI(r1^2+r2^2+r1r2)h/3

球:

1. 全面积 T=4PIr^2

2. 体积 V=4PIr^3/3

球台:

1. 侧面积 S=2PIrh

2. 全面积 T=PI(2rh+r1^2+r2^2)

3. 体积 V=PIh(3(r1^2+r2^2)+h^2)/6

球扇形:

1. 全面积 T=PIr(2h+r0),h为球冠高,r0为球冠底面半径

2. 体积 V=2PIr^2h/3

 

2.   线段问题

A.给你两个线段(八个点),求这两个线段的位置关系,如果相交,求出交点。

代码:

#include<iostream>

using namespace std;

struct point

{

   double x;

   double y;

};

//判断是否共线叉乘

double gongxian(point a,point b,point c)

{

    return((a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y));

}

//判断是否平行

int  judge(point a,point b,point c,point d)

{

    if((gongxian(a,b,c))==0&&(gongxian(b,c,d))==0)

        return 0;//说明共线

    else if( ((a.x-b.x)*(c.y-d.y)-(a.y-b.y)*(c.x-d.x))==0 )

        return -1;//平行

    else

        return 1;//相交

}

//求两线段的交点利用叉乘

void jiaodian(point a,point b,point c,point d)

{

    double a1,a2,b1,b2,c1,c2;

    a1=a.y-b.y;b1=b.x-a.x;c1=a.x*b.y-b.x*a.y;

    a2=c.y-d.y;b2=d.x-c.x;c2=c.x*d.y-d.x*c.y;

    point p;

    p.x=(c1*b2-c2*b1)/(a2*b1-a1*b2);

    p.y=(a2*c1-a1*c2)/(a1*b2-a2*b1);

    printf("两线段相交于( %.2f,%.2f)\n",p.x,p.y);

}

int main()

{

    int n;

    point p0,p1,p2,p3;

    scanf("%d",&n);

    while(n--)

    {

        //输出八个点确定两条线段

        scanf("%lf%lf%lf%lf",&p0.x,&p0.y,&p1.x,&p1.y);

        scanf("%lf%lf%lf%lf",&p2.x,&p2.y,&p3.x,&p3.y);

        double t=judge(p0,p1,p2,p3);

        if(t==0)

            printf("两线段共线\n");

        if(t==-1)

            printf("两线段平行\n");

        if(t==1)

            jiaodian(p0,p1,p2,p3);

    }

    return 0;

}

B.点到线段的距离

#include <iostream>

#include <cstdio>

#include <cmath>

#include <algorithm>

using namespace std;

const double eps = 1e-6;

 

double xmult(double x0,double y0,double x1,double y1,double x2,double y2)

{

   return(x0-x2)*(y1-y2)-(x1-x2)*(y0-y2);

}

 

double distance(double x1,double y1,double x2,double y2)

{

    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

}

 

double disptoseg(double x0,double y0,double x1,double y1,double x2,double y2)//x0,y0是点

{

    double x3=x0,y3=y0;

    x3+=y1-y2,y3+=x2-x1;

    if(xmult(x1,y1,x3,y3,x0,y0)*xmult(x2,y2,x3,y3,x0,y0)>eps)

        return distance(x0,y0,x1,y1)<distance(x0,y0,x2,y2)?distance(x0,y0,x1,y1):distance(x0,y0,x2,y2);

    return fabs(xmult(x0,y0,x1,y1,x2,y2))/distance(x1,y1,x2,y2);//如果单独使用这个就是点到直线的距离

}

 

int main()

{

    double x0,y0,x1,y1,x2,y2;

    while(~scanf("%lf%lf",&x0,&y0))

    {

        cout<<"请输入线段两点"<<endl;

       scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);

       double t= disptoseg(x0,y0,x1,y1,x2,y2)+eps;

       printf("%.3f\n",t);

    }

    return 0;

}

3.   匹克定理

----在一个平面坐标系中计算图形内的点(都是整点)的个数----

//匹克定理S = A + E/2 - 1

//S表示多边形面积

//A表示多边形内部的点的个数

//E表示在多边形上的点的个数

//A = S - E/2 + 1

#include<cstdio>

#include<algorithm>

#include<cmath>

using namespace std;

//最大公约数

int gcd(int a,int b)

{

    if(!b)

              return a;

    else

              return gcd(b, a%b);

}

//叉乘等于三角形面积的两倍

int area(int x1,int y1,int x2,int y2,int x3,int y3)

{

    return abs((x1-x2) * (y2-y3) - (x2-x3) * (y1-y2));

}

//计算边上的点的个数

int edga(int x1,int y1,int x2,int y2,int x3,int y3)

{

    int sum= 0;

       sum+= gcd(abs(x1-x2), abs(y1-y2));

       sum+= gcd(abs(x2-x3), abs(y2-y3));

       sum+= gcd(abs(x3-x1), abs(y3-y1));

       return sum;

}

 

int main()

{

    int x1,y1,x2,y2,x3,y3,i,j,s,e,a;

    while(scanf("%d%d%d%d%d%d", &x1, &y1, &x2, &y2, &x3, &y3))

    {

              if(x1==0&&y1==0 && x2==0 && y2==0&& x3==0 && y3==0)

              {

                     break;

              }

        s=area(x1,y1,x2,y2,x3,y3)/2;

        e=edga(x1,y1,x2,y2,x3,y3);

        a=s-e/2+1;

        printf("%d\n",a);

    }

    return 0;

}

4.   多边形面积

 

给你n条边数,再给出每条边对应的点(前提必须按顺序,如不按顺序就得凸包);

#include<iostream>

#include<stdio.h>

#include<math.h>

using namespace std;

 

int a[1000005],b[1000005];

__int64 sum;

 

int main()

{

    int tcase,i,j,len;

    scanf("%d",&tcase);

    while(tcase--)

    {

        cout<<"输入多边形n=:";

        cin>>len;

        for(i=0;i<len;i++)

        {

           scanf("%d%d",&a[i],&b[i]);

        }

        sum=0;a[len]=a[0];b[len]=b[0];

        for(i=0;i<len;i++)

        {

            sum+=a[i]*b[i+1]-a[i+1]*b[i];

        }

        if(sum<0)

            sum=-sum;

        if(sum%2==0)

            printf("%I64d\n",sum/2);

        else

            printf("%I64d.5\n",sum/2);

        }

    return 0;

}

求三角形面积可以用叉乘还可以用海伦公式(只适用于三角形):

#include<iostream>

#include<stdio.h>

#include<math.h>

using namespace std;

//叉乘等于三角形面积的两倍

double area(double x1,double y1,double x2,double y2,double x3,double y3)

{

    return (abs)((x1-x2) * (y2-y3) - (x2-x3) * (y1-y2));

}

 

int main()

{

    int tcase;

    double x1,y1,x2,y2,x3,y3,a,b,c;

    scanf("%d",&tcase);

    while(tcase--)

    {

        cout<<"输入三角形三边坐标分别为:"<<endl;

        cin>>x1>>y1>>x2>>y2>>x3>>y3;

        a=sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));

        b=sqrt((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2));

        c=sqrt((x1-x3)*(x1-x3)+(y1-y3)*(y1-y3));

        double p=(a+b+c)/2;//半周长

        double s=sqrt(p*(p-a)*(p-b)*(p-c));

        printf("叉积求面积得:%.2f\n",area(x1,y1,x2,y2,x3,y3)/2);

        printf("海伦公式求面积得:%.2f\n",s);

    }

    return 0;

}

5.   多边形重心(质心)

#include<stdio.h>

#include<math.h>

#include<stdlib.h>

#include <algorithm>

#include <iostream>

#define eps 1e-8

using namespace std;

 

struct point

{

       double x , y ;

};

double Area( point p0 , point p1 ,point p2 )

{

       double area = 0 ;

       area =  p0.x * p1.y + p1.x * p2.y + p2.x * p0.y - p1.x * p0.y - p2.x * p1.y - p0.x * p2.y;

       return area / 2 ;

}

int main ()

{

point p0 , p1 , p2 ;

int n;

    double sum_x , sum_y , sum_area , area;

    while ( ~ scanf ("%d",&n ) )

    {

          sum_x = sum_y = sum_area = 0;

          scanf ("%lf%lf",&p0.x,&p0.y);

          scanf ("%lf%lf",&p1.x,&p1.y);

          for ( int i = 2 ; i < n ; ++ i )

          {

              scanf ( "%lf%lf" , &p2.x , &p2.y ) ;

              area = Area(p0,p1,p2) ;

              sum_area += area ;

              sum_x += (p0.x + p1.x + p2.x) * area ;

              sum_y += (p0.y + p1.y + p2.y) * area ;

              p1 = p2 ;

          }

          sum_x=sum_x / (sum_area * 3);

          sum_y=sum_y / (sum_area * 3) ;

          printf ( "%.3f %.3f\n" , sum_x +eps,  sum_y+eps);

    }

    return 0 ;

}

6.   三角形各种心

#include <iostream>

#include <cmath>

#include <algorithm>

#include<stdio.h>

using namespace std;

const double EPS = 1e-8;

//叉乘等于三角形面积的两倍

double area(double x1,double y1,double x2,double y2,double x3,double y3)

{

    return (abs)((x1-x2) * (y2-y3) - (x2-x3) * (y1-y2));

}

 

//两点间距离

double Distance( double x1,  double y1,  double x2,  double y2)

{

    return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));

}

//外心

void waixin(double x1,double y1,double x2,double y2,double x3, double y3)

{

  double s = 0.5*fabs((x2-x1)*(y3-y1) - (x3-x1)*(y2-y1));  //三角形面积

  double a = Distance(x1, y1, x2, y2);

  double b = Distance(x2, y2, x3, y3);

  double c = Distance(x3, y3, x1, y1);

  double r = a*b*c/(4*s);//外接圆半径

 

  double C1 = (x1*x1+y1*y1-x2*x2-y2*y2)/2.0;

  double C2 = (x1*x1+y1*y1-x3*x3-y3*y3)/2.0;

  double x0 = (C1*(y1-y3)-C2*(y1-y2))/((x1-x2)*(y1-y3)-(x1-x3)*(y1-y2))+EPS;//外接圆圆心x轴坐标

  double y0 = (C1*(x1-x3)-C2*(x1-x2))/((y1-y2)*(x1-x3)-(y1-y3)*(x1-x2))+EPS;//外接圆圆心y轴坐标

  printf("该三角形的外接圆半径为: %.3f\n该三角形的外心为 (%.3f,%.3f)\n",r,x0,y0);

}

 

double CrossProduct(double x1, double y1, double x2, double y2)

{

 return (x1*y2-x2*y1);

}

//垂心

void chuixin(double x1,double y1,double x2,double y2,double x3, double y3)

{

     double B1 = y2 - y1;

     double A1 = x2 - x1;

     double C1 = y1*y3 - y2*y3 + x1*x3 - x2*x3;

     double B2 = y3 - y1;

     double A2 = x3 - x1;

     double C2 = y1*y2 - y2*y3 + x1*x2 - x2*x3;

 

     double x0 = CrossProduct(C2, B2, C1, B1)/CrossProduct(A1, B1, A2, B2)+EPS;//调节精度垂心x轴坐标

     double y0 = CrossProduct(C1, A1, C2, A2)/CrossProduct(A1, B1, A2, B2)+EPS;//垂心y轴坐标

 

     printf("该三角形的垂心为(%.3f ,%.3f)\n", x0, y0);

}

//重心

void zhongxin(double x1,double y1,double x2,double y2,double x3,double y3)

{

    double A1=(x1+x2)/2;

    double B1=(y1+y2)/2;

    double C1=(x1+x3)/2;

    double D1=(y1+y3)/2;

 

    double t=((A1-C1)*(D1-y2)-(B1-D1)*(C1-x2))/((A1-x3)*(D1-y2)-(B1-y3)*(C1-x2));

    double x0=A1+(x3-A1)*t+EPS;

    double y0=B1+(y3-B1)*t+EPS;

 

    printf("该三角形的重心为(%.3f ,%.3f)\n",x0,y0);

}

//内心

void neixin(double x1,double y1,double x2,double y2,double x3,double y3)

{

    double m1=atan2(y2-y1,x2-x1);

       double n1=atan2(y3-y1,x3-x1);

       double A1=x1+cos((m1+n1)/2);

       double B1=y1+sin((m1+n1)/2);

 

    double m2=atan2(y1-y2,x1-x2);

       double n2=atan2(y3-y2,x3-x2);

       double C1=x2+cos((m2+n2)/2);

       double D1=y2+sin((m2+n2)/2);

 

    double t=((x1-x2)*(y2-D1)-(y1-y2)*(x2-C1))/((x1-A1)*(y2-D1)-(y1-B1)*(x2-C1));

    double x0=(A1-x1)*t+EPS;

    double y0=(B1-y1)*t+EPS;

    double r=area(x1,y1,x2,y2,x0,y0)/Distance(x1,y1,x2,y2);

    printf("该三角形的内接圆半径为: %.3f\n该三角形的内心为(%.3f , %.3f)\n",r,x0,y0);

}

//费马点到三角形三顶点距离之和最小的点

void fermentpoint(double x1,double y1,double x2,double y2,double x3, double y3)

{

    double step = fabs(x1) + fabs(y1) + fabs(x2) + fabs(y2) + fabs(x3) + fabs(y3);

    int i, j, k;

    double x0 = (x1+x2+x3)/3;

    double y0 = (y1+y2+y3)/3;

    while (step > EPS)

    {

        for (k = 0; k < 10; step /= 2, k ++)

        {

            for (i = -1; i <= 1; i ++)

            {

                for (j =- 1; j <= 1; j ++)

                {

                    double A1 = x0 + step * i;

                    double B1 = y0 + step * j;

                    if (Distance(x0,y0,x1,y1) + Distance(x0,y0,x2,y2) + Distance(x0,y0,x3,y3) > Distance(A1,B1,x1,y1) + Distance(A1,B1,x2,y2) + Distance(A1,B1,x3,y3))

                    {

                        x0=A1;y0=B1;

                    }

                }

            }

        }

    }

    printf("该三角形的费马点为(%.3f , %.3f)\n",x0,y0);

}

int main()

{

 double x1, y1, x2, y2, x3, y3;

 while (scanf("%lf%lf%lf%lf%lf%lf", &x1, &y1, &x2, &y2, &x3, &y3) != EOF)

 {

    printf("该三角形面积为: %.3f\n",area(x1,y1,x2,y2,x3,y3)/2) ;

    waixin(x1,y1,x2,y2,x3,y3);

    chuixin(x1,y1,x2,y2,x3,y3);

    zhongxin(x1,y1,x2,y2,x3,y3);

    neixin(x1,y1,x2,y2,x3,y3);

    fermentpoint(x1,y1,x2,y2,x3,y3);

 }

 return 0;

}

7.   多边形的费马点(凸包+费马点)

给你一个多边形不是按顺序输入的点求其费马点(卡随机淬火算法)

代码:

#include <algorithm>

#include <iostream>

#include <cstdlib>

#include <cstdio>

#include <cmath>

#include <ctime>

 

using namespace std;

 

typedef struct pnode

{

    double x,y,d;

}point;

point Pn,P[105];

 

double dist1( point a, point b )

{

    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));

}

 

double dist( point p, int N )

{

    double sum = 0.0;

    for ( int i = 0 ; i <= N ; ++ i )

        sum += dist1( p, P[i] );

    return sum;

}

 

double crossproduct( point a, point b, point c )

{

    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);

}

 

bool cmp1( point a, point b )

{

    if ( a.x == b.x ) return a.y < b.y;

    else return a.x < b.x;

}

 

bool cmp2( point a, point b )

{

    return crossproduct( P[0], a, b ) > 0;

}

 

bool cmp3( point a, point b )

{

    double cp = crossproduct( P[0], a, b );

    if ( cp == 0 ) {

        if ( crossproduct( P[0], a, Pn ) == 0 )

            return a.d > b.d;

        else return a.d < b.d;

    }else return cp > 0;

}

 

double Graham( int N )

{

    sort( P+0, P+N, cmp1 );

    sort( P+1, P+N, cmp2 );

    for ( int i = 1 ; i < N ; ++ i )

        P[i].d = dist1( P[0], P[i] );

    Pn = P[N-1];

    sort( P+1, P+N, cmp3 );

 

    int top = N;

    if ( N > 2 )

    {

        top = 2;

        for ( int i = 3 ; i < N ; ++ i )

        {

            while ( crossproduct( P[top-1], P[top], P[i] ) < 0 ) -- top;

            P[++ top] = P[i];

        }

        //删掉共线的点

        int now = 1;

        for ( int i = 2 ; i <= top ; ++ i )

        {

            if ( crossproduct( P[now-1], P[now], P[i] ) == 0 )

                P[now] = P[i];

            else P[++ now] = P[i];

        }

        top = now;

    }

 

    //随机增量逼近法

    point  t,s = P[0];

    double sp  = 10000.0,esp = 0.01;

    double temp,min = dist( s, top );

    while ( sp > esp )

    {

        int flag = 0;

        for ( int i = 0 ; i < 10 ; ++ i )

        {

            t = s;

            int R = rand()%361;

            t.x += sp*cos(double (R));

            t.y += sp*sin(double (R));

            temp = dist( t, top );

            if ( min > temp )

            {

                min = temp;

                s = t;

                flag = 1;

            }

        }

        if ( !flag ) sp /= 2.0;

    }

    printf("%.3f %.3f\n",s.x,s.y);

    return min;

}

 

int main()

{

    srand( time(NULL));

    int N;

    while (~scanf("%d",&N))

    {

        for ( int i = 0 ; i < N ; ++ i )

            scanf("%lf%lf",&P[i].x,&P[i].y);

        printf("%.3f\n",Graham( N ));

    }

    return 0;

}

8.   凸包问题

a.    平面上给你一些让你求围成的最大凸包,

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cmath>

#include <algorithm>

using namespace std;

const int N = 10005;

const double eps = 1e-8;

 

struct gPoint

{

    double x, y;

}p[N];

int n;

gPoint convex[N<<1];

int vCount;

 

int dbcmp(double x)

{

    if(x < -eps)

        return  -1;

    else  if(x > eps)

        return  1;

    else

       return  0;

}

 

bool cmp(const gPoint &a, const gPoint &b)

{

    if(dbcmp(a.x-b.x) == 0)

        return  dbcmp(a.y-b.y)<=0;

    else

        return  dbcmp(a.x-b.x)<=0;

}

 

double Dis(gPoint a, gPoint b)

{

    double tx=b.x-a.x;

    double ty=b.y-a.y;

    return  sqrt(tx*tx+ty*ty);

}

 

bool rCheck(const gPoint &a, const gPoint &b, const gPoint &c)

{

    double x1 = b.x - a.x;

    double y1 = b.y - a.y;

    double x2 = c.x - a.x;

    double y2 = c.y - a.y;

    double tmp = x1*y2-x2*y1;

    return  dbcmp(tmp) < 0;

}

 

void grahamScan()

{

    vCount = 2;

    convex[0] = p[0];

    if(n == 1)  return;

    convex[1] = p[1];

    for(int i = 2; i < n; i++)

    {

        while(vCount>=2 && rCheck(convex[vCount-2],convex[vCount-1], p[i]))

            vCount--;

        convex[vCount++] = p[i];

    }

    for(int i = n-2; i >= 0; i--)

    {

        while(vCount>=2 && rCheck(convex[vCount-2],convex[vCount-1], p[i]))

            vCount--;

        convex[vCount++] = p[i];

    }

}

 

int main()

{

    scanf("%d", &n);

    for(int i = 0; i < n; i++)  scanf("%lf%lf", &p[i].x, &p[i].y);

    sort(p, p+n, cmp);

    grahamScan();

    double ans = 0.0;

    cout<<"凸包各边点为:"<<endl;

    for(int i = 1; i < vCount; i++)

    {

        cout<<convex[i].x<<" "<<convex[i].y<<endl;

        ans+=Dis(convex[i-1], convex[i])+eps;

    }

    printf("凸包周长为 : %.3f\n", ans);

    return 0;

}

b.    求凸包中两点最大距离

#include <cmath>

#include <algorithm>

#include <iostream>

using namespace std;

#define MAXN 50005

 

struct Point

{

    int x, y;

}pset[MAXN],ch[MAXN];

 

bool cmp(Point a,Point b)

{

    return b.y<a.y||(a.y==b.y&&b.x<a.x);

}

 

int cross(Point a,Point b,Point c)

{

    return (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y);

}

 

void convex_hull(Point *p,Point *ch,int n,int &len)

{

    sort(p, p+n,cmp);

    ch[0]=p[0];

    ch[1]=p[1];

    int top=1;

    for(int i=2;i<n;i++)

    {

        while(top>0&&cross(ch[top],p[i],ch[top-1])<=0)

            top--;

        ch[++top]=p[i];

    }

    int tmp=top;

    for(int i=n-2;i>=0;i--)

    {

        while(top>tmp&&cross(ch[top],p[i],ch[top-1])<=0)

            top--;

        ch[++top]=p[i];

    }

    len=top;

}

 

int dist2(Point a,Point b)

{

    return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);

}

//前面的可以作为整数凸包模板

int rotating_calipers(Point *ch,int n)

{

    int q=1,ans=0;

    ch[n]=ch[0];

    for(int p=0;p<n;p++)

    {

        while(cross(ch[p+1],ch[q+1],ch[p])>cross(ch[p+1],ch[q],ch[p]))

            q=(q+1)%n;

        ans=max(ans,max(dist2(ch[p],ch[q]),dist2(ch[p+1],ch[q+1])));

    }

    return ans;

}

 

int main()

{

    int n, len;

    while(scanf("%d", &n)!=EOF)

    {

        for(int i = 0;i < n;i++)

        {

            scanf("%d %d",&pset[i].x,&pset[i].y);

        }

        convex_hull(pset,ch,n,len);

        for(int i=0;i<len;i++)

            cout<<ch[i].x<<" "<<ch[i].y<<endl;

        printf("%d\n",rotating_calipers(ch,len));

    }

    return 0;

}

c.     求两凸包点对距离最近

#include <iostream>

#include <string.h>

#include <algorithm>

#include <stdio.h>

#include <math.h>

 

using namespace std;

 

const int N=50000;

const double eps=1e-9;

const double INF=1e99;

 

struct Point

{

    double x,y;

};

 

Point P[N],Q[N];

 

double cross(Point A,Point B,Point C)

{

    return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x);

}

 

double dist(Point A,Point B)

{

    return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));

}

 

double multi(Point A,Point B,Point C)

{

    return (B.x-A.x)*(C.x-A.x)+(B.y-A.y)*(C.y-A.y);

}

 

//顺时针排序

void anticlockwise(Point p[],int n)

{

    for(int i=0;i<n-2;i++)

    {

        double tmp=cross(p[i],p[i+1],p[i+2]);

        if(tmp>eps) return;

        else if(tmp<-eps)

        {

            reverse(p,p+n);

            return;

        }

    }

}

 

//计算C点到直线AB的最短距离

double Getdist(Point A,Point B,Point C)

{

    if(dist(A,B)<eps) return dist(B,C);

    if(multi(A,B,C)<-eps) return dist(A,C);

    if(multi(B,A,C)<-eps) return dist(B,C);

    return fabs(cross(A,B,C)/dist(A,B));

}

 

//求一条直线的两端点到另外一条直线的距离,反过来一样,共4种情况

double MinDist(Point A,Point B,Point C,Point D)

{

    return min(min(Getdist(A,B,C),Getdist(A,B,D)),min(Getdist(C,D,A),Getdist(C,D,B)));

}

 

double Solve(Point P[],Point Q[],int n,int m)

{

    int yminP=0,ymaxQ=0;

    for(int i=0;i<n;i++)

       if(P[i].y<P[yminP].y)

          yminP=i;

    for(int i=0;i<m;i++)

       if(Q[i].y>Q[ymaxQ].y)

          ymaxQ=i;

    P[n]=P[0];

    Q[m]=Q[0];

    double tmp,ans=INF;

    for(int i=0;i<n;i++)

    {

        while(tmp=cross(P[yminP+1],Q[ymaxQ+1],P[yminP])-cross(P[yminP+1],Q[ymaxQ],P[yminP])>eps)

            ymaxQ=(ymaxQ+1)%m;

        if(tmp<-eps) ans=min(ans,Getdist(P[yminP],P[yminP+1],Q[ymaxQ]));

        else         ans=min(ans,MinDist(P[yminP],P[yminP+1],Q[ymaxQ],Q[ymaxQ+1]));

        yminP=(yminP+1)%n;

    }

    return ans;

}

 

int main()

{

    int n,m;

    while(cin>>n>>m)

    {

        if(n==0&&m==0) break;

        for(int i=0;i<n;i++)

           cin>>P[i].x>>P[i].y;

        for(int i=0;i<m;i++)

           cin>>Q[i].x>>Q[i].y;

        anticlockwise(P,n);

        anticlockwise(Q,m);

        printf("%.5f\n",min(Solve(P,Q,n,m),Solve(Q,P,m,n)));

    }

    return 0;

}

9.   点集最小圆覆盖(随机增量法)

给你n个点,求一个最小的圆把所有点覆盖了,这些点可以在圆上;

#include <cstdio>

#include <cstring>

#include <cmath>

#include <algorithm>

#include <cstdlib>

using namespace std;

#define N 505

struct POINT

{

    double x, y;

} p[N];

int n;

inline double dist(const POINT &a, const POINT &b)

{

    return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));

}

POINT circumcenter(POINT &a, POINT &b, POINT &c)

{

    POINT ret;

    double a1=b.x-a.x, b1=b.y-a.y, c1=(a1*a1+b1*b1)/2;

    double a2=c.x-a.x, b2=c.y-a.y, c2=(a2*a2+b2*b2)/2;

    double d = a1*b2 - a2*b1;

    ret.x = a.x + (c1*b2-c2*b1)/d;

    ret.y = a.y + (a1*c2-a2*c1)/d;

    return ret;

}

void solve()

{

    random_shuffle(p, p+n);  //随机化序列,std里面的随机函数

    POINT c;

    double r = 0;

    for (int i=1; i<n; i++)

    {

        if (dist(p[i], c) <= r) continue;

        c = p[i];

        r = 0;

        for (int j=0; j<i; j++)

        {

            if (dist(p[j], c) <= r) continue;

            c.x = (p[i].x+p[j].x)/2;

            c.y = (p[i].y+p[j].y)/2;

            r = dist(p[j], c);

            for (int k=0; k<j; k++)

            {

                if (dist(p[k], c) <= r) continue;

                c = circumcenter(p[i], p[j], p[k]);

                r = dist(p[i], c);

            }

        }

    }

    printf("%.2f %.2f %.2f\n", c.x, c.y, r);

}

int main()

{

    while (scanf(" %d", &n) == 1 && n)

    {

        for (int i=0; i<n; i++)

            scanf(" %lf %lf", &p[i].x, &p[i].y);

        solve();

    }

    return 0;

}

10. 两圆相交的面积

#include<cmath>

#include<iomanip>

#include<algorithm>

#include <iostream>

using namespace std;

 

int main()

{

    double d,t,t1,area,x,y,xx,yy,r,rr;

    while(cin>>x>>y>>r)

    {

        cin>>xx>>yy>>rr;

        d=sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy));

        if(d>=r+rr)

           area=0;

        else if(d<=fabs(r-rr))

           area=min(acos(-1.0)*r*r,acos(-1.0)*rr*rr);

        else

        {

           t=(r*r+d*d-rr*rr)/2.0/d;

           t1=sqrt(r*r-t*t);

           area=-d*t1+r*r*acos(t/r)+rr*rr*acos((d-t)/rr);

        }

        cout<<fixed<<setprecision(3)<<area<<endl;

    }

    return 0;

}

 

posted on 2015-08-18 16:05  与我同在  阅读(352)  评论(0编辑  收藏  举报

导航