(一)计算几何基础(下)

6. 多边形
6.1 三角形

面积 :
(1) 通过叉积计算: cross(v1,v2)
(2) 海伦公式:p = (a+b+c)/2 s = sqrt(p(p-a)(p-b)(p-c));

四心:
(1)外心,外接圆圆心:三边中垂线交点,到三角形三个顶点的距离相等。
(2)内心:角平分线交点,到三边距离相等
(3)垂心:三条垂线的交点
(4)重心:三条中线的交点(到三角形三顶点距离的平方和最小的点,三角形内到三边距离之积最大的点。

6.2 普通多边形

通常按逆时针存储所有点。
凸多边形,简单多边形,多边形
凸多边形:过该多边形的任意一边做一条直线,如果其他各个顶点都在这条直线的同侧,则把这个多边形叫做凸多边形。

凸多边形求面积,判断多边形是否为凸多边形(详见例题)

//求多边形的面积(不一定是凸多边形)
double polygon_area(Point p[],int n)
{
	double s = 0;
	for(int i = 1;i+1<n;i++)
	{
		s+=cross(p[i]-p[0],p[i+1]-p[i]);
	}
	return s/2;
}
6.3 皮克定理

计算点阵中顶点在格点上的多边形面积公式:
S = a+b/2–1;
a:多边形内部的点数,b:多边形边上的点数 ,s:多边形的面积

7. 圆

(1)圆与直线的交点
(2)两圆交点
(3) 点到圆的切线
(4) 两圆公切线
(5)两圆相交面积

原题链接

例题一

在这里插入图片描述
其实就是求两个线段之间的距离,(要注意相交的时候距离为0,不相交的时候要分情况讨论)
另外,在做题时不要盲目抄模板,有可能模板不适用于这道题,要因题而异,自己思考:(详情见代码注释)
AC code:

#include<bits/stdc++.h>
using namespace std;

const double eps = 1e-10;
struct Point
{
    double x,y;
    Point (double x = 0,double y = 0): x(x),y(y) {};
};
#define Vector Point

Vector operator-(Vector A,Vector B)
{
    return {A.x-B.x,A.y-B.y};
}
int sign(double x)
{
    if(fabs(x)<eps)
        return 0;
    if(x<eps)
        return -1;
    return 1;
}
double dot(Vector a,Vector b)
{
    return a.x*b.x+a.y*b.y;
}
double get_length(Vector a)
{
    return sqrt(dot(a,a));
}
double cross(Vector a,Vector b)
{
    return a.x*b.y-a.y*b.x;
}
bool on_segment(Point p,Point a,Point b)
{
    return sign(cross(p-a,p-b))==0&&sign(dot(p-a,p-b))<=0;
}
bool segment_intersection(Point a1,Point a2,Point b1,Point b2)
{
    //跨立实验
    double c1 = cross(a2-a1,b1-a1);
    double c2 = cross(a2-a1,b2-a1);
    double c3 = cross(b2-b1,a2-b1);
    double c4 = cross(b2-b1,a1-b1);
    //利用叉积,四个点围成的两个三角形的叉积小于等于0
    return sign(c1)*sign(c2)<=0&&sign(c3)*sign(c4)<=0;
}
double get_point(Point a,Point b)
{
    Point c = {b.x-a.x,b.y-a.y};
    return sqrt(dot(c,c));//注意两点之间距离公式如何推
}
double distance_to_line(Point p,Point a,Point b)
{
    Vector v1 = b-a,v2 = p-a;
    return fabs(cross(v1,v2)/get_length(v1));
}
double distance_to_segment(Point p,Point a,Point b)
{
    //v2,v3因题目而异,模板只能参考,比如这里v3 = p-a,会wa
    Vector v1 = b-a,v2 = p-a,v3 = b-p;//三个向量
    // cout<<dot(v1,v2)<<" "<<dot(v1,v3)<<endl;
    //如果点p在线段ab的外面且离a较近
    if(sign(dot(v1,v2))<=0) return get_length(v2);
    //如果点p在线段ab的外面且离b较近
    if(sign(dot(v1,v3))<=0) return get_length(v3);
    //如果点p在线段ab的里面直接计算点到直线的距离就行了
    return distance_to_line(p,a,b);
}
double distance(Point a,Point b,Point c,Point d)
{//两个线段之间的最短距离
    double res1 = distance_to_segment(a,c,d);
    double res2 = distance_to_segment(b,c,d);
    double res3 = distance_to_segment(c,a,b);
    double res4 = distance_to_segment(d,a,b);
    // cout<<res1<<" "<<res2<<" "<<res3<<" "<<res4<<endl;
    double minn = res1;
    if(minn>res2)
        minn = res2;
    if(minn>res3)
        minn = res3;
    if(minn>res4)
        minn = res4;
    return minn;
}
int main()
{
    int q;
    cin>>q;
    while(q--)
    {
        double x1,y1,x2,y2,x3,y3,x4,y4;
        cin>>x1>>y1>>x2>>y2>>x3>>y3>>x4>>y4;
        Point a(x1,y1);
        Point b(x2,y2);
        Point c(x3,y3);
        Point d(x4,y4);
        //先判断四点是否共线
        Vector v1 = a-c;
        Vector v2 = b-c;
        Vector v = d-c;
        //分别对a,b点判断
        if(sign(cross(v,v1))==0&&sign(cross(v,v2))==0)
        {
            //四点共线
            if(on_segment(a,c,d)||on_segment(b,c,d)||on_segment(c,a,b)||on_segment(d,a,b))
            {
                printf("%.10lf\n",1);
            }
            else
            {
                printf("%.10lf\n",distance(a,b,c,d));
            }
        }
        else
        {
            if(segment_intersection(a,b,c,d))
            {
                printf("%.10lf\n",1);
            }
            else
            {
                printf("%.10lf\n",distance(a,b,c,d));
            }
        }
    }
    return 0;
}


原题链接

例题二:

在这里插入图片描述
其实就是验证该多边形是不是一个凸多边形。
想法:枚举一遍所有点,如果存在叉积小于0的三角形,那么就不是一个凸多边形。
AC code:

#include<bits/stdc++.h>
using namespace std;
struct Point
{
    double x, y;
    Point(double x = 0, double y = 0) : x(x), y(y) {}
};
const int N = 110;Point p[N];int n,q;
double x,y;
const double eps = 1e-8;
typedef Point Vector;
Vector operator - (Point A, Point B) {return Vector(A.x - B.x, A.y - B.y);}
double cross(Point a,Point b)
{
    return a.x*b.y-a.y*b.x;
}
int main()
{
    cin>>q;
    for(int i = 0;i<q;i++)
    {
        cin>>x>>y; p[i] = {x,y};
    }
    for(int i = 2;i<q;i++)
    {
        double area = cross(p[i-1]-p[i-2] ,p[i]-p[i-2]);
        if(area<0)//这里可以用sign符号函数进行判断是否小于eps
        {
            cout<<0<<endl;
            return 0;
        }
    }
    if(cross(p[q-1]-p[q-2],p[0]-p[q-2])<0)//这里可以用sign符号函数进行判断是否小于eps
    {//这是对于最后两个点和第一个点之间形成的三角形面积进行判断
        cout<<0<<endl;
        return 0;
    }
    cout<<1<<endl;
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值