Computational Geometry + Euler's Theorem (one stroke)

The main idea of ​​the title:
Given multiple points in turn (the first point and the last point are required to overlap), connect the two points before and after to find the number of faces of the final figure.

Thought analysis:

With the help of Euler's theorem, V+FE = 2, the number of faces can be calculated only by the number of points and the number of edges. The number of points can only be enumerated by straight lines, but there may be duplicate points, the most deduplicated One click will do, and then the remaining points in the enumeration appear in a few lines.

Code sample: (untested)

#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 - point = vector
    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 represents a vector

//dot product
double Dot(Vector a, Vector b){return a.x*b.x+a.y*b.y;}

// length of line segment
double Lenth(Vector a){return sqrt(Dot(a, a));}

//The included angle of the vector (radians)
double Angle(Vector a, Vector b){return acos(Dot(a, b)/Lenth(a)/Lenth(b));}

// cross product
double Cross(Vector a, Vector b){return a.x*b.y-a.y*b.x;}

// 2 times the directed area of ​​the triangle
double Area2(point a, point b, point c){return Cross(b-a, c-a);}

//Vector rotation, a is the angle of counterclockwise rotation
// rad is in radians
point Rotate(Vector a, double rad){
    return point(ax*cos(rad)-ay*sin(rad), ax*sin(rad)+ay*cos(rad));
}

// Calculate the unit normal of the vector
point Normal(Vector a){
    double L = Lenth(a);
    return point(-a.y/L, a.x/L);
}

// intersection of two lines
// The two straight lines are p+tv, q+tw, where p, q are a point on the two straight lines, v, w are the vectors in the direction of the straight lines,
// The parameter of the intersection point on the first line is t1, and the parameter of the second line is t2
// t1 = (cross(w,u)/cross(v,w));  t2 = (cross(v,u)/cross(v,w));
// Before calling, make sure that the two lines have a unique intersection, if and only if the two lines are not collinear
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);
}

// distance from point to line
double Dis(point p, point a, point b){
    Vector v1 = b-a, v2 = p-a;
    return fabs(Cross(v1, v2)/Lenth(v1));
}

// distance from point to line segment
//The projection of point p on the line may or may not be on the line
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); // Note the size is greater than the sign
    if (dcmp(Dot(v1, v3))>0) return Lenth(v3);
    else return fabs(Cross(v1, v2)/Lenth(v1));
}

// point projection on line segment
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);
}

//Determine the intersection of line segments (the intersection point is not at the end point, and the two lines have only a unique intersection point)
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;
}
//The intersection of line segments is determined to determine whether the endpoint is on another straight line (the intersection point is not at the position of the endpoints of the two straight lines)
bool OneInter(point p, point a1, point a2){
    return dcmp(Cross(a1-p, a2-p))==0 && dcmp(Dot(a1-p, a2-p))<0;
}
// Depending on the question, whether the two straight lines have overlapping endpoints is specially judged

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--; // last point is starting point    
    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\n", e-c+2);
    return 0;
}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325214894&siteId=291194637