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