文章目录
计算几何基础
平面几何距离
- 曼哈顿距离:
int dist(int x1,int y1,int x2,int y2)
{
int dx=abs(x1-x2);
int dy=abs(y1-y2);
return dx+dy;
}
- 欧几里得距离:
double dist(double x1,double y1,double x2,double y2)
{
double dx=x1-x2;
double dy=y1-y2;
return sqrt(dx*dx+dy*dy);
}
其中,pow函数是比较慢的,这里没有必要使用。
圆的周长和面积
圆与圆之间的关系:
海伦公式计算三角形面积
点到直线的距离
- 那么向量如何求解这个问题:
- 例题:1286
#include<bits/stdc++.h>
using namespace std;
//求距离
double dist(double x1,double y1,double x2,double y2)
{
double dx=x1-x2,dy=y1-y2;
return sqrt(dx*dx+dy*dy);
}
void solve()
{
double xa,ya,xb,yb,xc,yc;cin>>xa>>ya>>xb>>yb>>xc>>yc;
//把向量处理出来,ca,cb
double xca=xa-xc,yca=ya-yc;
double xcb=xb-xc,ycb=yb-yc;
//叉乘
double ans=abs(xca*ycb-xcb*yca)/dist(xa,ya,xb,yb);
cout<<fixed<<setprecision(2)<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int i;cin>>i;
while(i--)solve();
return 0;
}
- 总结:
- 封装函数,按照输入的组别来处理。
- 在这个函数中处理出两条边叉乘的结果。
- 最终的结果是叉乘结果的绝对值除以两者之间的距离。
- 求距离再次封装一个函数:使用欧几里得算法。
- 注意使用double类型以及保留小数位数。
- 例题:求三角形面积–1231
#include<bits/stdc++.h>
using namespace std;
using ll =long long;
//求距离
double dist(double x1,double y1,double x2,double y2)
{
double dx=x1-x2,dy=y1-y2;
return sqrt(dx*dx+dy*dy);
}
void solve()
{
double x1,y1,x2,y2,x3,y3;cin>>x1>>y1>>x2>>y2>>x3>>y3;
long double a=dist(x1,y1,x2,y2);
long double b=dist(x1,y1,x3,y3);
long double c=dist(x2,y2,x3,y3);//开了一次根号,再求一次根号很容易导致精度误差
long double p=(a+b+c)/2;
long double ans=sqrt(p*(p-a)*(p-b)*(p-c));
cout<<fixed<<setprecision(2)<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int i;cin>>i;
while(i--)solve();
return 0;
}
点积和叉积
- 概念:
- 点积的代码实现:
#include<bits/stdc++.h>
using namespace std;
struct Point{//定义点的结构体
double x,y;
Point(){}
Point(double x,double y):x(x),y(y){}
Point operator+(Point p){return Point(x+p.x,y+p.y);}
Point operator-(Point p){return Point(x-p.x,y-p.y);}
Point operator*(double a){return Point(x*a,y*a);}
Point operator/(double a){return Point(x/a,y/a);}
Point operator*(Point p){return Point(x*p.x+y*p.y);}//点积
};
typedef Point Vector;
int main()
{
Vector a(1.0,3.0);
Vector b(2.0,4.0);
double dot_product=a*b;//使用重载的*运算符计算点积
cout<<dot_product<<endl;
return 0;
}
- 叉积
- 代码实现:
#include<bits/stdc++.h>
using namespace std;
struct Point{//定义点的结构体
double x,y;
Point(){}
Point(double x,double y):x(x),y(y){}
//乘法
Point operator*(double a){return Point(x*a,y*a);}
//点乘
Point operator*(Point p){return Point(x*p.x+y*p.y);}//点积
double cross(const Point &p)const{return x*p.y-y*p.x;}
};
typedef Point Vector;
int main()
{
Vector a(1.0,3.0);
Vector b(2.0,4.0);
double dot_product=a*b;//使用重载的*运算符计算点积
cout<<dot_product<<endl;
double cross_product=a.cross(b);
cout<<cross_product<<endl;
return 0;
}
例题:
- 怎么判断两条边是否垂直呢?
点积为0即可。
#include<bits/stdc++.h>
using namespace std;
struct Point{//定义点的结构体
double x,y;
Point():x(0),y(0) {} //初始化
//两点相减,得到向量
double operator-(const Point &p)const{return x-p.x,y-p.y};
Point(double x,double y):x(x),y(y){}
//点积
double dot(const Point &p)const{return x*p.x-y*p.y;}
// 判断当前的向量和另一向量是否垂直
bool ischui(const Point &p)const{
return fabs(dot(p))<1e-10;//点积为0即垂直
}
};
int main()
{
int n,k,count=0;
cin>>n>>k;
for(int i=0;i<n;i++){
Point start,turn,end;
cin>>start.x>>start.y;
cin>>turn.x>>turn.y;
cin>>end.x>>end.y;
// 计算两个向量
Point v1=turn-start;
Point v2=end-turn;
// 检查是否垂直
if(ischui(v2)){
count++;
}
// 计算上取整
int result=(count+k-1)/k;
cout<<result<<end;
return 0;
}
}
点和线的关系
点的表示形式和代码
//使用pair存储
using Point =pair<int,int>;
//使用结构体
struct Point{
int x,y;
};
判断点在直线的那边
点到线的垂足
点到线的距离
例题-1242
#include<bits/stdc++.h>
using namespace std;
struct Point{
double x;
double y;
};
inline double cross(const Point& p1,const Point& p2)
{
return p1.x*p2.y-p2.x*p1.y;
}
int main()
{
int n;
Point p1,p2,p3;
cin>>n;
while(n--)
{
cin>>p1.x>>p1.y>>p2.x>>p2.y>>p3.x>>p3.y;
cout<<(cross(p1,p2)+cross(p2,p3)+cross(p1,p3)==0?"Yes":"No")<<endl;
}
return 0;
}
inline表示建议编译器将cross函数的实现直接插入到调用它的地方,以提高性能。
例题-1240
#include <bits/stdc++.h>
using namespace std;
void solve(){
double xa,ya,xb,yb,xc,yc;
cin>>xa>>ya>>xb>>yb>>xc>>yc;
double xAB=xb-xa,yAB=yb-ya;
double xBC=xb-xc,yBC=yb-yc;
double p=xAB*yBC-xBC*yAB;
if(p==0){
cout<<"IN"<<"\n";
}
else if(p>0){
cout<<"R"<<"\n";
}
else{
cout<<"L"<<"\n";
}
}
int main()
{
int t;cin>>t;
while(t--)solve();
return 0;
}
总结:遇到直线用向量比较好。
升级–点到线段的距离–1285
?:这时候还能不能做垂线呢?
能。且点到直线的距离有一个垂足,判断垂足是否在线段AB内。
#include <bits/stdc++.h>
using namespace std;
double dist(double x1,double y1,double x2,double y2){
double dx=x1-x2,dy=y1-y2;
return sqrt(dx*dx+dy*dy);
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;cin>>t;
while(t--){
double xa,ya,xb,yb,xc,yc;
cin>>xa>>ya>>xb>>yb>>xc>>yc;
if((yb-ya)/(xb-xa)!=(yc-yb)/(xc-xb)){
double xCA=xa-xc,yCA=ya-yc;
double xCB=xb-xc,yCB=yb-yc;
double ans=abs(xCA*yCB-xCB*yCA)/dist(xa,ya,xb,yb);
cout<<fixed<<setprecision(2)<<ans<<"\n";
}
else{
double d1=dist(xa,ya,xc,yc);
double d2=dist(xb,yb,xc,yc);
cout<<fixed<<setprecision(2)<<min(d1,d2)<<"\n";
}
}
return 0;
}
- 题解逻辑;
- 当斜率不相等时,利用点到直线的距离公式求距离。
- 当斜率相等时,也就是说c在直线AB上,求ca和cb的最小值。
任意多边形面积的计算
平面向量
向量积
- 内积:
- 外积:
求任意多边形的面积:
- 求三角形的面积
#include<bits/stdc++.h>
using namespace std;
using ll =long long;
//求距离
double dist(double x1,double y1,double x2,double y2)
{
double dx=x1-x2,dy=y1-y2;
return sqrt(dx*dx+dy*dy);
}
void solve()
{
double x1,y1,x2,y2,x3,y3;cin>>x1>>y1>>x2>>y2>>x3>>y3;
long double a=dist(x1,y1,x2,y2);
long double b=dist(x1,y1,x3,y3);
long double c=dist(x2,y2,x3,y3);//开了一次根号,再求一次根号很容易导致精度误差
long double p=(a+b+c)/2;
long double ans=sqrt(p*(p-a)*(p-b)*(p-c));
cout<<fixed<<setprecision(2)<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int i;cin>>i;
while(i--)solve();
return 0;
}