简单的计算几何

1 向量

这里就不介绍向量的加法和减法,着重介绍一下向量的叉积的作用和代码实现
a), 可以判断点在直线的左边还是右边 ad: POJ2318(当时poj挂了进不去)
b), 计算三角形的面积 ( 两个向量的叉积的1/2的绝对值 )
c),在计算凸包中起到了重要作用 ( 下面会讲 )
当然了可能会用到一些重载 详情请参见 kuang_bin.blog

三角形

a). 求三角形的面积
方法一:海伦公式

p=(a+b+c)/2;S=p(pa)(pb)(pc)=14(a+b+c)(a+bc)(a+cb)(b+ca) p = ( a + b + c ) / 2 ; S = p ∗ ( p − a ) ∗ ( p − b ) ∗ ( p − c ) = 1 4 ( a + b + c ) ( a + b − c ) ( a + c − b ) ( b + c − a )

方法二:
Sabc=|12ABAC| S △ a b c = | 1 2 ∗ A B → ∗ A C → |

b). 判断点是否在三角形内
面积法 : Sabc=Spbc+Sapc+Sabp S △ a b c = S △ p b c + S △ a p c + S △ a b p
叉积法:可以利用叉积的正负号判断,这一结论可以扩展到凸多边形

多边形

a) . 凸多边形面积的求法:把凸多边形分成n-2个小三角形然后求面积 ( 对非凸多边形仍然有效 )
代码实现:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>

using namespace std;

const int maxn = 1e5+5;

//已知所有的点 
struct node{
    int x,y;
}ss[maxn];

//利用叉积求面积 
double cross(node a,node b,node c){
    return (c.x-a.x)*(b.y-a.y)-(b.x-c.x)*(c.y-a.y);
}

double Areas(node *s,int n){
    double area = 0;
    for (int i = 1;i<n-1;i++) {
        area += cross(s[0],s[i],s[i+1]); 
    }
    return fabs(area / 2.0);//因为最后可能方向反了所以求一下绝对值 
}

int main(){
    int n; cin>>n;
    for (int i = 0;i<n;i++) scanf("%d %d",&ss[i].x,&ss[i].y);
    double areas = Areas(ss,n);
    printf("%.lf\n",areas); 
    return 0;
}

b).pick公式求多边形内部定点数

S()=a()+12b()1 S ( 多 边 形 面 积 ) = a ( 多 边 形 内 部 的 点 数 ) + 1 2 b ( 多 边 形 边 上 的 点 数 ) − 1

对于一个左闭右开的线段它的点数为 gcd(abs(ByAy),abs(BxAx)) g c d ( a b s ( B y − A y ) , a b s ( B x − A x ) )

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 1e5+5;

//现在已知一个多边形所有的点 

struct node{
    int x,y;
}ss[maxn];

double cross(node a,node b,node c){
    return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}

double Areas(node *s,int n){
    double area = 0;
    for (int i = 1;i<n-1;i++){
        area += cross(s[0],s[i],s[i+1]);
    }
    return fabs(area / 2.0);  //因为可能总的方向反了,所以求一下绝对值 
}

int gcd(int a,int b){
    if(b == 0){
        return a;
    } else {
        return gcd(b,a%b);
    }
}

int PGIV(node *s,int n){  //pick_get_inner_vertix
    int num = 0;
    double areas = Areas(s,n);
    int edNode = 0;
    for (int i = 1;i<n;i++) {
        edNode += gcd(abs(ss[i].y-ss[i-1].y),abs(ss[i].x-ss[i-1].x));
    }
    edNode += gcd(abs(ss[0].y-ss[n-1].y),abs(ss[0].x-ss[n-1].x));
    int inNode = (2*(areas+1)-edNode) / 2;
    return inNode;
}

int main(){
    int n; cin>>n;
    for (int i = 0;i<n;i++) scanf("%d %d",&ss[i].x,&ss[i].y);
    printf("%d\n",PGIV(ss,n));
    return 0;
}

凸包

凸包就是把给定点包围在内部的、面积最小的凸多边形。
Andrew算法:
首先把所有点按照从小到大排序(如果x相同,按照y从小到大排
序),删除重复点后得到序列p1; p2……,然后把p1和p2放到凸包
中。从p3开始,当新点在凸包“前进”方向的左边时继续,否则
依次删除最近加入凸包的点,直到新点在左边。
从左到右和从右到左各扫描一次
计算凸包,输入点数组p,个数n,输出点数组ch。函数返回凸包顶点数
输入不能有重复点。函数执行完之后输入点被破坏
如果不希望在凸包的边上有输入点,把两个<=改成<
在精度要求高时建议用用自定义函数dcmp

代码实现:

struct node
{
    int x,y;
}ss[maxn],ans[maxn];

int n,m;

bool cmp(node a,node b)
{
    return (a.x<b.x)||(a.x==b.x&&a.y<b.y);
}

int cross(node a,node b,node c)
{
    return (b.x-a.x)*(c.y-b.y)-(b.y-a.y)*(c.x-b.x);
}

int Andrew()
{
    int len,top = 2;
    sort(ss,ss+n,cmp);
    ans[0] = ss[0],ans[1] = ss[1];
    for(int i=2;i<n;i++)
    {
        while( top>1 && cross(ans[top-1],ans[top-2],ss[i])<=0) top--;
        ans[top++]=ss[i];
    }
    len = top;
    for(int i=n-2;i>=0;i--)
    {
        while( top > len && cross(ans[top-1],ans[top-2],ss[i])<=0) top--;
        ans[top++] = ss[i];
    }
    return top;
}

易错点

几何问题通常的WA点就是精度问题 可以自己写一个eps

const double eps =1e-10;
int dcmp ( double x){
    if( fabs (x)<eps ) return 0;
    else return x <0? -1:1;
}
ACM 很全的计算几何模板 基础部分 1.几何公式 5 1.1三角形 5 1.2四边形 5 1.3正n边形 5 1.4圆 5 1.5棱柱 6 1.6棱锥 6 1.7棱台 6 1.8圆柱 6 1.9圆锥 6 1.10圆台 7 1.11球 7 1.12球台 7 1.13球扇形 7 2.直线与线段 7 2.0预备函数 7 2.1判三点是否共线 8 2.2判点是否在线段上 9 2.3判断两点在线段的同一侧 9 2.4判断两点是否在线段的异侧 9 2.5点关于直线的对称点 10 2.7判断两线段是否相交 10 2.7.1常用版 10 2.7.2不常用版 11 2.8 两条直线的交点 11 2.9点到直线的最近距离 12 2.10点到线段的最近距离 12 3.多边形 12 3.0 预备浮点函数 12 3.1判定是否是凸多边形 13 3.2判定点是否在多边形内 14 3.3 判定一条线段是否在一个任意多边形内 15 4. 三角形 16 4.0预备函数 16 4.1三角形的外心 17 4.2三角形内心 17 4.3三角形垂心 17 5. 圆 18 5.0预备函数 18 5.1判定直线是否与圆相交 19 5.2判定线段与圆相交 19 5.3判圆和圆相交 19 5.4计算圆上到点p最近点 19 5.5计算直线与圆的交点 20 5.6计算两个圆的交点 20 6. 球面 21 6.0给出地球经度纬度,计算圆心角 21 6.1已知经纬度,计算地球上两点直线距离 21 6.2已知经纬度,计算地球上两点球面距离 21 7. 三维几何的若干模板 22 7.0预备函数 22 7.1判定三点是否共线 23 7.2判定四点是否共面 23 7.1判定点是否在线段上 23 7.2判断点是否在空间三角形上 24 7.3判断两点是否在线段同侧 24 7.4判断两点是否在线段异侧 25 7.5判断两点是否在平面同侧 25 7.6判断两点是否在平面异侧 25 7.7判断两空间直线是否平行 25 7.8判断两平面是否平行 26 7.9判断直线是否与平面平行 26 7.10判断两直线是否垂直 26 7.11判断两平面是否垂直 26 7.12判断两条空间线段是否相交 27 7.13判断线段是否与空间三角形相交 27 7.14计算两条直线的交点 28 7.15计算直线与平面的交点 28 7.16计算两平面的交线 29 7.17点到直线的距离 29 7.18 计算点到平面的距离 29 7.19计算直线到直线的距离 30 7.20空间两直线夹角的cos值 30 7.21两平面夹角的cos值 30 7.22直线与平面夹角sin值 31 1.最远曼哈顿距离 31 2. 最近点对 32 3. 最近点对 34 4. 最小包围圆 36 5. 两个圆的交点 39 6. 三角形外接圆圆心 40 7. 凸包 42 8.凸包卡壳旋转出所有对踵点、最远点对 44 9. 凸包+旋转卡壳平面面积最大三角 47 10. Pick定理 50 11. 多边形面积和重心 51 12. 判断一个简单多边形是否有核 52 13. 模拟退火 54 14. 六边形坐标系 56 15. 用一个给定半径的圆覆盖最多的点 60 16. 不等大的圆的圆弧表示 62 17. 矩形面积并 62 18. 矩形的周长并 66 19. 最近圆对 70 20. 两个圆的面积交 74
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值