zoukankan      html  css  js  c++  java
  • 计算几何 + 欧拉定理 (一笔画)

    题目大意:
    依次给定多个点(要求第一个点和最后一个点重叠),把前后两个点相连求最后得到的图形的面的个数

    思路分析 :

    借助欧拉定理,V+F-E = 2,只要求出点的数量和边的数量就可以计算出面的数量,点的数量只要枚举直线就可以,但是有可能有重复的点,之最去重一下就可以,然后在枚举剩下的点出现在几条直线中。

    代码示例:(未测试)

    #define ll long long
    const double eps = 1e-10;
    const double pi = acos(-1.0);
    
    struct point
    {
        double x, y;
        point(double _x, double _y):x(_x), y(_y){}
        
        // 点-点=向量
        point operator-(const point &v){
            return point(x-v.x, y-v.y);
        }
    
    };
    
    int dcmp(double x){
        if (fabs(x)<eps) return 0;
        else return x<0?-1:1;
    }
    bool operator == (const point &a, const point &b){
        return (dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0); 
    }
    
    typedef point Vector; // Vector表示向量
    
    //点积
    double Dot(Vector a, Vector b){return a.x*b.x+a.y*b.y;}
    
    //线段的长度
    double Lenth(Vector a){return sqrt(Dot(a, a));}
    
    //向量的夹角(弧度)
    double Angle(Vector a, Vector b){return acos(Dot(a, b)/Lenth(a)/Lenth(b));}
    
    //叉积
    double Cross(Vector a, Vector b){return a.x*b.y-a.y*b.x;}
    
    //三角形有向面积的2倍
    double Area2(point a, point b, point c){return Cross(b-a, c-a);}
    
    //向量旋转,a为逆时针旋转的角度
    // rad是弧度
    point Rotate(Vector a, double rad){
        return point(a.x*cos(rad)-a.y*sin(rad), a.x*sin(rad)+a.y*cos(rad));
    }
    
    //计算向量的单位法线
    point Normal(Vector a){
        double L = Lenth(a);
        return point(-a.y/L, a.x/L);
    }
    
    // 两条直线的交点
    // 两条直线为 p+tv, q+tw,其中p, q为两直线上的一点, v,w是直线所在方向的向量,
    // 交点在第一条直线的参数为t1, 第二条直线的参数为t2
    // t1 = (cross(w,u)/cross(v,w));  t2 = (cross(v,u)/cross(v,w));
    // 调用前要确保两直线有唯一交点,当且仅当两直线不共线
    point Getline(point p, Vector v, point q, Vector w){
        point u = p-q;
        double t = Cross(w, u)/Cross(v, w);
        return point(p.x+v.x*t, p.y+v.y*t);
    }
    
    //点到直线的距离
    double Dis(point p, point a, point b){
        Vector v1 = b-a, v2 = p-a;
        return fabs(Cross(v1, v2)/Lenth(v1));
    }
    
    //点到线段的距离
    //点p在直线的投影可能在直线上,也可能不在直线上
    double Dis2(point p, point a, point b){
        if (a==b) return Lenth(p-a);
        Vector v1=b-a, v2 = p-a, v3=p-b;
        if (dcmp(Dot(v1, v2))<0) return Lenth(v2); // 注意大小于号
        if (dcmp(Dot(v1, v3))>0) return Lenth(v3);
        else return fabs(Cross(v1, v2)/Lenth(v1));
    }
    
    //点在线段上的投影
    point Getline2(point p, point a, point b){
        Vector v = b-a;
        double f = Dot(v, p-a)/Dot(v, v);
        return point(a.x+v.x*f, a.y+v.y*f);
    }
    
    //线段相交判定(交点不在端点的位置,且两直线仅有唯一交点)
    bool Inter(point a1, point a2, point b1, point b2){
        double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1),
               c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
        return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
    }
    //线段相交判定,判定端点是否在另一条直线上(交点不在两直线端点得位置)
    bool OneInter(point p, point a1, point a2){
        return dcmp(Cross(a1-p, a2-p))==0 && dcmp(Dot(a1-p, a2-p))<0;
    }
    // 视题目要求是否特判两直线有端点重合的情况
    
    vector<point>p, v;
    bool cmp(point a, point b){
        if (a.x == b.x) return a.y<b.y;
        else return a.x<b.x; 
    }
    int main() {
        int n;
        double x, y;
        
        cin >> n;
        for(int i = 1; i <= n; i++){
            scanf("%lf%lf", &x, &y);
            p.push_back(point(x, y));
            v.push_back(point(x, y));
        }
        v.push_back(point(x, y));
        n--; // 最后一个点是起点    
        for(int i = 0; i < n; i++){
            for(int j = i+1; j < n; j++){
                if (Inter(p[i], p[i+1], p[j], p[j+1])) {
                    v.push_back(Getline(p[i], p[i+1]-p[i], p[j], p[j+1]-p[j]));
                }
            }
        }
        sort(v.begin(), v.end(), cmp);
        v.erase(unique(v.begin(), v.end()), v.end());
        int c = v.size();
        int e = n;
        for(int i = 0; i < c; i++){
            for(int j = 0; j < n; j++){
                if (OneInter(v[i], p[j], p[j+1])) e++;
            }
        }
        printf("%d
    ", e-c+2);
        return 0;
    }
    
    东北日出西边雨 道是无情却有情
  • 相关阅读:
    由于空间,注定的结果——第五届山东省ACM编程比赛总结
    GPS 偏移校正(WGS-84) 至(GCJ-02) java版本号以实现
    IM设计与实现的系统模块的聊天记录
    Android数据存储——SQLite数据库(模板)
    JAVA多线程和并发基础面试问答
    好博客
    浅谈Java中的equals和==
    JVM的内存区域划分
    try,catch,finally
    Java 如何有效地避免OOM:善于利用软引用和弱引用
  • 原文地址:https://www.cnblogs.com/ccut-ry/p/8982801.html
Copyright © 2011-2022 走看看