zoukankan      html  css  js  c++  java
  • 简单的计算几何

    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)=14(a+b+c)(a+b−c)(a+c−b)(b+c−a)


    方法二:

    Sabc=|12ABAC|S△abc=|12∗AB→∗AC→|


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

    多边形

    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
    ",areas); 
        return 0;
    }

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

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


    对于一个左闭右开的线段它的点数为gcd(abs(ByAy),abs(BxAx))gcd(abs(By−Ay),abs(Bx−Ax))

    #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
    ",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;
    }
  • 相关阅读:
    Atcoder D
    51nod 1201 整数划分(dp)
    Atcoder D
    Atcoder C
    codeforces 812 E. Sagheer and Apple Tree(树+尼姆博弈)
    codeforces 811 D. Vladik and Favorite Game(bfs水题)
    codeforces 811 E. Vladik and Entertaining Flags(线段树+并查集)
    codeforces 811 C. Vladik and Memorable Trip(dp)
    1449 砝码称重(思维)
    SQL大量数据查询的优化 及 非用like不可时的处理方案
  • 原文地址:https://www.cnblogs.com/Nlifea/p/11745979.html
Copyright © 2011-2022 走看看