zoukankan      html  css  js  c++  java
  • 《训练指南》——8.3

      LA3263:

      题目大意:给出一个一笔画图形,它包含n个点。先给出其n个点坐标之后,求解这个图形把平面分成了几个区域。

      分析:这里要求的是面的个数,显然连直接暴力进行求解的方法都没有,因此这里就需要进行一定的转化,已知信息是点的坐标,那么我们应该能够想到平面几何中的欧拉定理(我们将图形看成图论当中的图G),经过这一步转换,我们需要做的就是求解图形的点数和边数。

      点:显然这里我们就需要设置暴力,以确保能够完成所有相交情况的筛查。穷举之后,原来的节点数加交点数(去重后)就是该图中的总结点数v.

      边:结合欧拉定理的适用条件,这里需要注意的是“边”的两个节点的直接连线。

      

      

      简单的参考代码如下:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    
    using namespace std;
    
    const double eps = 1e-8;
    
    int dcmp(double x){if(fabs(x)<eps) return 0; return (x<0)?-1:1;}
    
    struct Point
    {
        double x,y;
        Point(double _x=0,double _y=0):x(_x),y(_y){};
    };
    
    Point operator+(Point A,Point B) {return Point(A.x+B.x,A.y+B.y);}
    Point operator-(Point A,Point B) {return Point(A.x-B.x,A.y-B.y);}
    Point operator*(Point A,double p) {return Point(A.x*p,A.y*p);}
    Point operator/(Point A,double p) {return Point(A.x/p,A.y/p);}
    bool operator<(const Point&a,const Point&b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
    bool operator==(const Point&a,const Point&b){return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;}
    
    double Dot(Point A,Point B) {return A.x*B.x+A.y*B.y;}  //点积
    double Cross(Point A,Point B) {return A.x*B.y-A.y*B.x;} //叉积
    
    //P+tv和Q+tw的交点
    Point GetLineIntersection(Point P,Point v,Point Q,Point w)
    {
        Point u=P-Q;
        double t=Cross(w,u)/Cross(v,w);
        return P+v*t;
    }
    
    //判断规范相交
    bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)
    {
        double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1);
        double c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);
    
        return dcmp(c1)*dcmp(c2) < 0&&dcmp(c3)*dcmp(c4)< 0;
    }
    
    //判断点p是否在线段a1a2上
    bool OnSegment(Point p,Point a1,Point a2)
    {
        return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
    }
    
    int n;
    Point pt[1000];
    vector<Point> vp;
    
    int main()
    {
        int cas=1;
        while(scanf("%d",&n)!=EOF&&n)
        {
            vp.clear();
            for(int i=0;i<n;i++)
            {
                scanf("%lf%lf",&pt[i].x,&pt[i].y);
                vp.push_back(pt[i]);
            }
            n--;
            for(int i=0;i<n;i++)
            {
                for(int j=i+1;j<n;j++)
                {
                    if(SegmentProperIntersection(pt[i],pt[i+1],pt[j],pt[j+1]))
                    {
                        vp.push_back(GetLineIntersection(pt[i],pt[i+1]-pt[i],pt[j],pt[j+1]-pt[j]));
                    }
                }
            }
            sort(vp.begin(),vp.end());
            int c=unique(vp.begin(),vp.end())-vp.begin();
            int e=n;
            int cc=0;
            for(vector<Point>::iterator it=vp.begin();cc<c&&it!=vp.end();cc++,it++)
            {
                for(int i=0;i<n;i++)
                {
                    if(OnSegment(*it,pt[i],pt[i+1])) e++;
                }
            }
            printf("Case %d: There are %d pieces.
    ",cas++,e+2-c);
        }
        return 0;
    }

     

       看完代码读者可能会疑惑,这里求解交点真的可以用简单的规范相交吗?我们不要忘记了规范相交的定义,只要交点不是端点的情况,都是可以用规范相交的方法表示的,这里我们计算节点数已经单独将端点拿出,因此用规范相交判断相交并计数的正确的。

  • 相关阅读:
    nginx转发域名小记
    简化kubernetes应用部署工具之Helm应用部署
    docker-compose的使用
    使用二进制包安装k8s
    搭建k8s(一)
    linux环境下安装使用selenium Chrome
    常用User-Agent大全
    缓存之Memcache
    git-commit Angular规范
    Kubernetes介绍及基本概念
  • 原文地址:https://www.cnblogs.com/rhythmic/p/5731355.html
Copyright © 2011-2022 走看看