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;
}