纯小白蓝桥杯备赛笔记--DAY14(计算几何)

计算几何基础

平面几何距离

在这里插入图片描述

  • 曼哈顿距离:
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;
}
  • 总结:
  1. 封装函数,按照输入的组别来处理。
  2. 在这个函数中处理出两条边叉乘的结果。
  3. 最终的结果是叉乘结果的绝对值除以两者之间的距离。
  4. 求距离再次封装一个函数:使用欧几里得算法。
  5. 注意使用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;
}

二维计算几何基础

参考文献

  • 39
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值