LA 3263 That Nice Euler Circuit 好看的一笔画 几何问题

LA 3263 好看的一笔画

平面上有一个包含n个顶点的一笔画,让求闭合曲线形成的图形将整个平面分成了几部分。


解题思路:

1,首先这题要转换思路利用到欧拉定理

欧拉定理:设平面图的顶点数、边数、和面数分别为V、E、F则V+F-E=2

那么面数为F = E+2-V

2,理解定理之后接下来的处理就是,记录相交生成的交点,删除重复的交点

3,最后就是求出有多少条线段、如果一个点出现在一个线段上(除了端点)、那么就多加一条边

4,用了《训练指南》上的模版,感觉这样写非常好


#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 310 ;
struct Point{
    double x,y ;
    Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vector ;
Point P[maxn] ;
Point V[maxn*maxn] ;
bool operator < (const Point& a, const Point& b) {///排序:x自然排序,y自然排序
  return a.x < b.x || (a.x == b.x && a.y < b.y);
}
Vector operator + (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}
Vector operator - (Point A,Point B){return Vector(A.x-B.x,A.y-B.y);}
Vector operator * (Vector A,double p){return Vector(A.x*p,A.y*p);}
double Cross(Vector A,Vector B){return A.x*B.y - A.y*B.x ;}
double Dot(Vector A,Vector B){return A.x*B.x + A.y*B.y ;}
const double eps = 1e-10 ;
int dcmp(double x){
    if(fabs(x)<eps)return 0;
    else return x<0?-1:1 ;
}
bool operator == (const Point& a, const Point &b) {///这个函数是unique函数中重载了==符号
  return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
}
bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2){
    double c1 = Cross(a2-a1,b1-a1) ;
    double c2 = Cross(a2-a1,b2-a1) ;
    double c3 = Cross(b2-b1,a1-b1) ;
    double c4 = Cross(b2-b1,a2-b1) ;
    return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0 ;
}
bool OnSegment(Point p,Point a1,Point a2){return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0 ;}
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w){
    Vector u = P-Q ;
    double t = Cross(w,u)/Cross(v,w) ;
    return P+v*t ;
}
int main(){
    int cas = 1 ;
    int n ;
    while(~scanf("%d",&n),n){
        for(int i=0;i<n;i++){
            scanf("%lf%lf",&P[i].x,&P[i].y);
            V[i] = P[i] ;
        }
        n-- ;///最后一个点和第一个点相同
        int c = n ;
        int e = n ;
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                if(SegmentProperIntersection(P[i],P[i+1],P[j],P[j+1])){///判断任意两条线段是否相交
                    V[c++] = GetLineIntersection(P[i],P[i+1]-P[i],P[j],P[j+1]-P[j]);///如果相交了就获得一个交点
                }
            }
        }
        sort(V,V+c) ;///对点进行排序
        c = unique(V,V+c)-V ;///除去相同的点,返回值是不重复的元素最后一个元素的地址
        for(int i=0;i<c;i++){///对于一个点,如果他在另外的一条线段上出现,那么这条线段就相当于被分为两段
            for(int j=0;j<n;j++){
                if(OnSegment(V[i],P[j],P[j+1])){
                    e++ ;
                }
            }
        }
        printf("Case %d: There are %d pieces.\n",cas++ ,e+2-c);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值