uvalive LA3263

LA 3263 That Nice Euler Circuit

题目大意:给定n个点组成的图,求图上的面F的数量。

细节方面:这个上面的线段是不会有重叠的情况的,任意两个相邻的线段是不会平行的,有可能有三个线共点。

解题思路:首先这道题要通过欧拉定理解决;

欧拉定理:E,V,F分别代表平面图的边,顶点,面,V+F-E=2;

所以,求E,V:

V包括相邻的线段的端点和不相邻线段的交点,都可以直接求解。

对于交点,有可能有相同的两个,删除相同的其中一个。

原有的线段有部分被交点截断,所以判断所有的顶点是不是在原有线段上,来判断线段截断的情况,截断一次加一条边。

题目没有清楚地表达相邻两线段不会平行,所以没分析出来考虑周全的算法。这是学习白书上的算法。

#include <cmath>
#include <stdio.h>
#include <iostream>
#include <algorithm>
using namespace std;
struct Point{
    double x,y;
    Point(double x,double y):x(x),y(y){}
    Point(){}
};
typedef Point Vector;
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 D){return Point(a.x*D,a.y*D);}
Point operator/(Point a,double D){return Point(a.x/D,a.y/D);}
bool operator<(Point a,Point b){if(a.x!=b.x) {return a.x<b.x;} else return 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){return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;}
/*
 dot        向量间的点积
 length     向量的模
 angle      向量间的夹角弧度
 cross      向量间的叉积
 area2      三点围成三角形有向面积的两倍
 rotate     向量绕起点逆时针旋转一定弧度后的向量
 normal     求向量的单位法线
*/
double dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
double length(Vector a){return sqrt(dot(a,a));}
double angle(Vector a,Vector b){return acos( dot(a,b)/length(a)/length(b) );}
double cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
double area2(Point A,Point B,Point C){return cross(B-A,C-A);}
Vector rotate(Vector a,double rad){
  return Vector(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));
}
Vector normal(Vector a){double l=length(a);return Vector(-a.y/l,a.x/l);}

int segmentProperInersection(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;
}

Point getIntersection(Point P,Vector v,Point Q,Vector w)
{
    Vector u=P-Q;
    double t=cross(w,u)/cross(v,w);
    return P+v*t;
}
bool OnSegment(Point p,Point a1,Point a2)
{
    return dcmp(cross(a1-p,a2-p))==0&&dcmp(dot(a1-p,a2-p))<0;
}
const int maxn = 350;
Point po[maxn],V[maxn*maxn];
int main()
{
    //freopen("in.txt","r",stdin);
    int n,cas=0;
    while(scanf("%d",&n)==1 && n){

        for(int i=0;i<n;i++)
        {
            scanf("%lf%lf",&po[i].x,&po[i].y);
            V[i]=po[i];
        }
        int c=n-1,E=n-1,F=0;
        for(int i=0;i<n-1;i++)
        {

            for(int j=i+1;j<n-1;j++)
            {

                if(segmentProperInersection(po[i],po[i+1],po[j],po[j+1]))
                {
                    V[c++]=getIntersection(po[i],po[i+1]-po[i],po[j],po[j+1]-po[j]);
                }
            }
        }

        sort(V,V+c);
        c=unique(V,V+c)-V;
        for(int i=0;i<c;i++)
            for(int j=0;j<n-1;j++)
                if(OnSegment(V[i],po[j],po[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、付费专栏及课程。

余额充值