您的位置:首页 > 其它

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

2015-08-18 16:05 495 查看

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

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
;

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
=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
,Q
;

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
=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
;

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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: