• LA3263计算几何+欧拉定理的应用+线段交判边


      1 /*LA3263计算几何+欧拉定理的应用+线段交判边
      2 欧拉定理:顶点+边数-面数=2
      3 思路:先找到枚举的范围,减少判断的集合,再筛选。
      4 巧妙之处:线段间产生的点如果被夹在原先定点的连线上,则产生一条新的边
      5 易错处:
      6 1、给出的第一个点和最后一个点是重合的,所以最终有n-1个初始点
      7 2、应该统一所有的点,在去重,因为新增点可能和给定点相同
      8 3、结构体重载== 时注意精度处理
      9 */
     10 #include <stdio.h>
     11 #include <stdlib.h>
     12 #include <string.h>
     13 #include <math.h>
     14 #include <ctype.h>
     15 #include <string>
     16 #include <iostream>
     17 #include <sstream>
     18 #include <vector>
     19 #include <queue>
     20 #include <stack>
     21 #include <map>
     22 #include <list>
     23 #include <set>
     24 #include <algorithm>
     25 #define INF 0x3f3f3f3f
     26 #define LL long long
     27 #define eps 1e-7
     28 using namespace std;
     29 
     30 struct Point
     31 {
     32     double x,y;
     33     Point(double x=0,double y=0):x(x),y(y){}
     34 };
     35 typedef Point Vector;
     36 int dcmp(double x)
     37 {
     38     if(fabs(x) < eps)return 0;
     39     else return x < 0 ? -1 : 1;
     40 }
     41 bool operator < (const Point &a, const Point &b)
     42 {
     43     return a.x < b.x || (a.x == b.x && a.y < b.y);
     44 }
     45 bool operator == (const Point& a, const Point &b)
     46 {
     47     return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
     48 }
     49 
     50 Vector operator-(Point A,Point B)//表示A指向B
     51 {
     52     return Vector(A.x-B.x,A.y-B.y);
     53 }
     54 Vector operator*(Vector A,double k)
     55 {
     56     return Vector(A.x*k,A.y*k);
     57 }
     58 Vector operator+(Point A,Point B)//表示A指向B
     59 {
     60     return Vector(B.x+A.x,B.y+A.y);
     61 }
     62 
     63 double Dot(Vector A,Vector B)
     64 {
     65     return A.x*B.x+A.y*B.y;
     66 }
     67 double Length(Vector A)
     68 {
     69     return sqrt(Dot(A,A));
     70 }
     71 double Angle(Vector A,Vector B)
     72 {
     73     return fabs(acos(Dot(A,B)/Length(A)/Length(B)));
     74 }
     75 double Cross(Vector A,Vector B) {return A.x*B.y-A.y*B.x;}
     76 double Area(Point A,Point B,Point C)//三角形面积
     77 {
     78     return  Cross(B-A,C-A)/2;
     79 }
     80 bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2)
     81 {
     82     double c1 = Cross(a2-a1,b1-a1), c2 = Cross(a2-a1, b2-a1);
     83     double c3 = Cross(b2-b1,a1-b1), c4 = Cross(b2-b1, a2-b1);
     84     return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
     85 }
     86 Point GetLineIntersection(Point P, Vector v, Point Q, Vector w)
     87 {
     88     Vector u = P-Q;
     89     double t = Cross(w, u) / Cross(v, w);
     90     return P+v*t;//在精度要求极高的情况下,可以考虑自定义分数类
     91 }
     92 bool OnSegment(Point p, Point a1, Point a2)
     93 {
     94     return dcmp(Cross(a1-p, a2-p))==0 && dcmp(Dot(a1 - p ,a2 - p) < 0);//含端点就是<=0
     95 }
     96 int n,cas=0;
     97 vector<Point>P;
     98 vector<Point>np;
     99 int main()
    100 {//欧拉公式:顶点+边数-面数=2
    101     while(cin>>n && n)
    102     {
    103         cas++;
    104         P.clear();
    105         np.clear();
    106         for(int i=0;i<n;i++)
    107         {
    108             int x,y;
    109             cin>>x>>y;
    110             P.push_back(Point(x,y));
    111             np.push_back(Point(x,y));//把给定点也加入的原因是:后来的连线也可能穿过给定的点。容易犯错!
    112         }
    113         n--;//这是一个坑,因为第一个和最后一个点相同
    114         int v,e=n;//v是输入的顶点,e是在被分割前一定有n条边
    115         for(int i=0;i<n;i++)
    116         for(int j=i+1;j<n;j++)
    117         {
    118             if (SegmentProperIntersection(P[i],P[i+1],P[j],P[j+1]))//暴力枚举线段相交
    119             {
    120                 np.push_back(GetLineIntersection(P[i],P[i+1]-P[i],P[j],P[j+1]-P[j]));
    121             }
    122         }
    123         sort(np.begin(),np.end());
    124         int cnt=unique(np.begin(),np.end())-np.begin();
    125         v=cnt;
    126         for(int i=0;i<cnt;i++)//枚举每个新的点是否分割一条原来的线段,实际上,多次枚举的原因是去除多线共点的问题,不然就可以直接用数量计算出来
    127         {
    128             for(int j=0;j<n;j++)//注意原先线段必然是连续的点构成
    129             {
    130                 if ( OnSegment(np[i], P[j], P[j+1] ) ) e++;//点在线段上但不在端点上
    131             }
    132         }
    133         printf("Case %d: There are %d pieces.
    ",cas,e+2-v);
    134     }
    135     return 0;
    136 }
  • 相关阅读:
    BZOJ 3028 食物 ——生成函数
    BZOJ 1933 [Shoi2007]Bookcase 书柜的尺寸 ——动态规划
    论咸鱼的自我修养之网络流
    SPOJ LCS2 Longest Common Substring II ——后缀自动机
    SPOJ NSUBSTR Substrings ——后缀自动机
    BZOJ 1879 [Sdoi2009]Bill的挑战 ——状压DP
    BZOJ 1875 [SDOI2009]HH去散步 ——动态规划 矩阵乘法
    BZOJ 1226 [SDOI2009]学校食堂Dining ——状压DP
    BZOJ 4566 [Haoi2016]找相同字符 ——广义后缀自动机
    BZOJ 3473 字符串 ——广义后缀自动机
  • 原文地址:https://www.cnblogs.com/little-w/p/3574383.html
Copyright © 2020-2023  润新知