ACM 常用几何基本数学公式

ACM常用几何基本数学公式

1.   海伦公式求面积

公式描述:公式中a,b,c分别为三角形三边长,p为半周长,S为三角形的面积。

2.   矢量向量求面积

3.   点到直线的距离公式

方法一:距离公式直接求

公式描述:公式中的直线方程为Ax+By+C=0,点P的坐标为(x0,y0)。但是直线方程不是够直接。推荐使用方法二。

方法二:先用海伦公式求面积然后求三角形高

4.   点到线段的距离公式[或:点到线段最近的点]

有以下四种情况:

  • 点在线段上,距离为0;
  • 线段是一个点,用两点公式求;
  • 三点构成直角三角形或者钝角三角形,那么直角或者钝角即为点到线段最近的点;
  • 三点构成锐角三角形,那么距离为三角形的高,点到线段最近的点。

以下是具体代码, 代码已经在 51 Nod 1298  圆与三角形 测试过了。

#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;

//#pragma comment(linker, "/STACK:1024000000,1024000000")

#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
#define fst             first
#define snd             second

typedef __int64  LL;
//typedef long long LL;
typedef unsigned int uint;
typedef pair<int, int> PII;

const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
const int MAXN = 3 + 5;
const int MAXM = 600 + 5;

// 判断浮点数与0的大小关系
int sgn(double x) {
    if (fabs(x) < eps) return 0;
    if (x < 0) return -1;
    else return 1;
}

struct Point {
    double x, y;
    Point() {}
    Point(double _x, double _y) : x(_x), y(_y) {}
} pc, p[MAXN];

typedef Point Vect;
/**
 * 两点距离公式
 *
 */
double getDist(const Point &p1, const Point &p2) {
    int tx = p1.x - p2.x;
    int ty = p1.y - p2.y;
    return sqrt(tx * tx + ty * ty);
}

/**
 * 由两点求向量
 *
 */
Vect getVect(const Point& p1, const Point &p2) {
    return Vect(p2.x - p1.x, p2.y - p1.y);
}

/**
 * 求矢量叉积
 * @param  v1 [description]
 * @param  v2 [description]
 * @return    [description]
 */
double xmult(const Vect& v1, const Vect& v2) {
    return v1.x * v2.y - v2.x * v1.y;
}

/**
 * 矢量叉积求面积
 *
 */
double getArea1(const Point &p0, const Point &p1, const Point &p2) {
    Vect v1 = getVect(p0, p1);
    Vect v2 = getVect(p0, p2);
    return 0.5 * getVectProduct(v1, v2);
}
/**
 * 海伦公式求面积
 *
 */
double getArea2(const Point &p0, const Point &p1, const Point &p2) {
    double p0p1 = getDist(p0, p1);
    double p0p2 = getDist(p0, p2);
    double p1p2 = getDist(p1, p2);
    double x = (p0p1 + p0p2 + p1p2) / 2.0;
    return sqrt(x * (x - p0p1) * (x - p0p2) * (x - p1p2));
}
/**
 * 利用海伦公式或者叉积公式求点到直线的距离
 * @param  p0 [点]
 * @param  p1 [直线上的点1]
 * @param  p2 [直线上的点2]
 * @return    [点到直线的距离]
 */
double point2line(const Point &p0, const Point &p1, const Point &p2) {
    double area = getArea1(p0, p1, p2);
    // double area = getArea2(p0, p1, p2);
    double p1p2 = getDist(p1, p2);
    return 2 * area / p1p2;
}
/**
 * 获取点到线段的最小距离
 * @param  p0 [点]
 * @param  p1 [线段端点1]
 * @param  p2 [线段端点2]
 * @return    [点到线段的距离]
 */
double point2lineSeg_Near(const Point &p0, const Point &p1, const Point &p2) {
    double p0p1 = getDist(p0, p1);
    double p0p2 = getDist(p0, p2);
    double p1p2 = getDist(p1, p2);
    // 点在线段上
    if (sgn(p0p1 + p0p2 - p1p2) == 0) return 0;
    // 线段两个端点p1,p2重合
    if (sgn(p1p2) == 0) return p0p1;
    // ∠p0p1p2 为直角或者钝角
    if (p0p2 * p0p2 >= p0p1 * p0p1 + p1p2 * p1p2) return p0p1;
    // ∠p0p2p1 为直角或者钝角
    if (p0p1 * p0p1 >= p0p2 * p0p2 + p1p2 * p1p2) return p0p2;
    // ∠p0p1p2 和 ∠p0p2p1 都是锐角,等价于求点到直线的距离
    return point2line(p0, p1, p2);
}
/**
 * 求点到线段的最长距离
 * @param  p0 [点]
 * @param  p1 [线段端点1]
 * @param  p2 [线段端点2]
 * @return    [最长距离]
 */
double point2lineSeg_Far(const Point &p0, const Point &p1, const Point &p2) {
    double p0p1 = getDist(p0, p1);
    double p0p2 = getDist(p0, p2);
    return max(p0p1, p0p2);
}

int T;
double R;

int main() {
#ifndef ONLINE_JUDGE
    FIN;
#endif // ONLINE_JUDGE
    scanf("%d", &T);
    while (T --) {
        scanf("%lf %lf %lf", &pc.x, &pc.y, &R);
        for (int i = 0; i < 3; i ++) {
            scanf("%lf %lf", &p[i].x, &p[i].y);
        }
        double mi[3], ma[3];
        mi[0] = point2lineSeg_Near(pc, p[0], p[1]);
        mi[1] = point2lineSeg_Near(pc, p[0], p[2]);
        mi[2] = point2lineSeg_Near(pc, p[1], p[2]);
        ma[0] = point2lineSeg_Far(pc, p[0], p[1]);
        ma[1] = point2lineSeg_Far(pc, p[0], p[2]);
        ma[2] = point2lineSeg_Far(pc, p[1], p[2]);
        bool suc = false;
        for (int i = 0; i < 3; i ++) {
            if (sgn(mi[i] - R) <= 0 && sgn(ma[i] - R) >= 0) {
                suc = true;
                break;
            }
        }
        puts(suc ? "Yes" : "No");
    }
    return 0;
}


5.   判断三点共线

判断三点共线的方法可以通过求斜率,求周长,求面积来判断。

  1. 通过斜率来判断:(ay-by)/(ax-bx) == (cy-by)/(cx-bx)需要比较判断分母不为0 的情况,而且还可能出现除法精度丢失。
  2. 通过周长来判断:若AC > AB>BC,判断 AC == AB+BC,求距离的时候会用到sqrt,丢失精度。
  3. 通过面积来判断:由上述的叉积求面积法来判断,面积为0,证明三点共线。

故,只需要判断即可。

6.判断四点是否共面

类似上面的方法, 可以根据体积来判断。 四个点构成三个向量, 如果这三个向量的混合积为0,那么体积为0,那么四点共面。

代码如下【包括了三维空间的点积、叉积、混合积的计算】,代码已经在 51Nod 1265四点共面  中测试过了。

#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;

//#pragma comment(linker, "/STACK:1024000000,1024000000")

#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
#define fst             first
#define snd             second

typedef __int64  LL;
//typedef long long LL;
typedef unsigned int uint;
typedef pair<int, int> PII;

const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
const int MAXN = 4 + 5;
const int MAXM = 600 + 5;
int sgn(double x) {
    if (fabs(x) < eps) return 0;
    if (x < 0) return -1;
    else return 1;
}
struct Point {
    double x, y, z;
};
typedef Point Vect;
int T;
Point pnts[MAXN];
/**
 * 三维空间中两点求向量
 *
 */
Vect getVect(const Point& p1, const Point& p2) {
    Vect v;
    v.x = p1.x - p2.x;
    v.y = p1.y - p2.y;
    v.z = p1.z - p2.z;
    return v;
}
/**
 * 求三维空间的两向量叉积 (v1 × v2)
 *
 */
Vect xMulti(const Vect& v1, const Vect& v2) {
    Vect v;
    v.x = v1.y * v2.z - v1.z * v2.y;
    v.y = v1.z * v2.x - v1.x * v2.z;
    v.z = v1.x * v2.y - v1.y * v2.x;
    return v;
}
/**
 * 求三维空间中的两向量点积 (v1 · v2)
 *
 */
double dotMulti(const Vect& v1, const Vect& v2) {
    return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
/**
 * 求三维空间中三个向量的混合积 (v1 × v2)·(v3)
 *
 */
double mixMulti(const Vect& v1, const Vect& v2, const Vect& v3) {
    return dotMulti(xMulti(v1, v2), v3);
}
/**
 * 判断四点是否共面
 * 根据混合积求体积,判断体积是否为0
 */
bool isInArea(const Point& p1, const Point& p2, const Point& p3, const Point& p4) {
    Vect p1p2, p1p3, p1p4;
    p1p2 = getVect(p1, p2);
    p1p3 = getVect(p1, p3);
    p1p4 = getVect(p1, p4);
    return sgn(mixMulti(p1p2, p1p3, p1p4)) == 0;
}
int main() {
#ifndef ONLINE_JUDGE
    FIN;
#endif // ONLINE_JUDGE
    scanf("%d", &T);
    while (T --) {
        for (int i = 0; i < 4; i ++) {
            scanf("%lf %lf %lf", &pnts[i].x, &pnts[i].y, &pnts[i].z);
        }
        bool ret = isInArea(pnts[0], pnts[1], pnts[2], pnts[3]);
        puts(ret ? "Yes" : "No");
    }
    return 0;
}

6.判断线段是否相交

代码已经在 51 nod 1264 线段相交 测试过了

#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;

//#pragma comment(linker, "/STACK:1024000000,1024000000")

#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
#define fst             first
#define snd             second

typedef __int64  LL;
//typedef long long LL;
typedef unsigned int uint;
typedef pair<int, int> PII;

const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
const int MAXN = 4 + 5;
const int MAXM = 600 + 5;

int sgn(double x) {
    if (fabs(x) < eps) return 0;
    if (x < 0) return -1;
    else return 1;
}

struct Point {
    double x, y;
    Point() {}
    Point(double _x, double _y) : x(_x), y(_y) {}
} pnts[MAXN];

typedef Point Vect;

Vect getVect(const Point& p1, const Point &p2) {
    return Vect(p2.x - p1.x, p2.y - p1.y);
}
double xMulti(const Vect& v1, const Vect& v2) {
    return v1.x * v2.y - v2.x * v1.y;
}
/**
 * 判断线段是否相交
 *
 */
bool segInter(const Point& p1, const Point& p2, const Point& p3, const Point& p4) {
    return max(p1.x, p2.x) >= min(p3.x, p4.x) &&
           max(p3.x, p4.x) >= min(p1.x, p2.x) &&
           max(p1.y, p2.y) >= min(p3.y, p4.y) &&
           max(p3.y, p4.y) >= min(p1.y, p2.y) &&
           sgn(xMulti(getVect(p3, p2), getVect(p1, p2))) * sgn(xMulti(getVect(p4, p2), getVect(p1, p2))) <= 0 &&
           sgn(xMulti(getVect(p1, p4), getVect(p3, p4))) * sgn(xMulti(getVect(p2, p4), getVect(p3, p4))) <= 0;
}

int T;

int main() {
#ifndef ONLINE_JUDGE
    FIN;
#endif // ONLINE_JUDGE
    scanf("%d", &T);
    while(T --) {
        for(int i = 0; i < 4; i ++) {
            scanf("%lf %lf", &pnts[i].x, &pnts[i].y);
        }
        bool ret = segInter(pnts[0], pnts[1], pnts[2], pnts[3]);
        puts(ret ? "Yes" : "No");
    }
    return 0;
}

补充链接:

时间: 2024-10-10 10:17:59

ACM 常用几何基本数学公式的相关文章

c++ ACM常用函数

1 保留小数点后两位 #include <iomanip> cout << setiosflags(ios::fixed) << setprecision(2)<< getAdd(num) << endl; 2 截取字符串 类似spilt #include <string> const char * spilt="/"; char *p; p=strtok(str,spilt); while(p!=NULL)  {

常用几何变换矩阵

参考: http://wenku.baidu.com/view/193f8a8fbceb19e8b8f6baf6.html (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu 转载请标明来源) 常用的几何变换矩阵:平移(translate),旋转(rotate),缩放(scale),以及简单的复合,如绕指定点旋转.缩放 关于矩阵复合时的乘法参考 http://blog.csdn.net/chunyexiyu/article/details/4467173

GPU编程中的常用几何函数、纹理映射函数、偏导数函数

在GPU编程中,函数一般分为以下几种类型:数学函数.几何函数.纹理映射函数.偏导数函数.调试函数等.熟练利用好GPU自带函数,可以在一定程度上提高并行编程速度与效率. 在上一部分已经介绍了数学函数, 数学函数用于执行数学上常用计算,比如:三角函数.幂函数.向量和矩阵函数,这些函数一般都被重载,用来支持标量数据和不同长度的向量作为输入参数.本部分介绍几何函数.纹理映射函数.偏导数函数.调试函数. 几何函数(Geometric Functions) 几何函数,如表所示,用于执行和解析几何相关的计算,

数学中常用几何画板绘制椭圆

圆锥曲线是高中数学的重点和难点,也是历来高考的必考内容,所以对于高中生来说,弄懂圆锥曲线这块难啃的骨头,是很有必要的.其中要熟练掌握的圆锥曲线之一就是椭圆,它是圆锥与平面的截线,其实要想画出椭圆,其方法不止一种,下面就一起来通过几何画板教程学学椭圆的五种画法. 方法一.利用椭圆第一定义构造椭圆 椭圆第一定义:平面内到两个定点的距离之和等于定长2a(a>0)的点的轨迹就是椭圆,按照此定义可画出椭圆,具体步骤如下: 1.单击“圆工具”,在画板的适当位置任意画一个圆,将圆心的标签改为F1.单击“点工具

ACM常用模板整理

线段树单点修改区间查询 #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 const int maxn=55555; struct segmentTree{ int sum; }tree[maxn<<2]; int per[

java语言的各种输入情况(ACM常用)

1.只输入一组数据: Scanner s=new Scanner(System.in); int a=s.nextInt(); int b=s.nextInt(); 2.输入有多组数据,没有说明输入几组数据,每组数据占一行: Scanner s=new Scanner(System.in); while(s.hasnext()){//判断是否数据结束 int a=s.nextInt(); int b=s.nextInt(); } 3.输入多组数据,第一行为一个整数N,表示有N组测试数据,后面的接

ACM常用模板

数论: 中国剩余定理(互质与非互质通用版) int m[3],r[3]; int e_gcd(int a,int b,int &x,int &y) { if(b==0) { x=1; y=0; return a; } int ans=e_gcd(b,a%b,x,y); int temp=x; x=y; y=temp-a/b*y; return ans; } int Zhong() { int M = m[0],R = r[0]; for(int i = 1; i < 3; i++)

ACM常用的Java代码

1 import java.util.*; 2 import java.io.*; 3 4 public class Main { 5 public static void main(String[] args) throws IOException{ 6 // 计算程序运行时间 7 // Arrays 8 long st = System.currentTimeMillis(); 9 if ("abc" == "abc") System.out.println(&

ACM常用STL容器

1 // STL(标准模板库),由三大部分组成:容器,算法,迭代器 2 3 4 // STL六大组件:container(容器),algorthm(算法),iterator(迭代器) 5 // function object(仿函数),adaptor(适配器),allocator(空间适配器) 6 7 // STL容器 8 9 // vector 10 // deque(双端数组) 11 // stack 12 // queue 13 // list(链表模型) 14 // priotry_qu