您的位置:首页 > 产品设计 > UI/UE

【LA3263】That Nice Euler Circuit——欧拉定理的应用

2016-04-08 11:33 337 查看
Little Joey invented a scrabble machine that he called Euler, after the great mathematician. In his

primary school Joey heard about the nice story of how Euler started the study about graphs. The

problem in that story was – let me remind you – to draw a graph on a paper without lifting your

pen, and finally return to the original position. Euler proved that you could do this if and only if the

(planar) graph you created has the following two properties: (1) The graph is connected; and (2) Every

vertex in the graph has even degree.

Joey’s Euler machine works exactly like this. The device consists of a pencil touching the paper,

and a control center issuing a sequence of instructions. The paper can be viewed as the infinite

two-dimensional plane; that means you do not need to worry about if the pencil will ever go off the

boundary.

In the beginning, the Euler machine will issue an instruction of the form (X0, Y 0) which moves the

pencil to some starting position (X0, Y 0). Each subsequent instruction is also of the form (X′, Y ′),

which means to move the pencil from the previous position to the new position (X′, Y ′), thus draw a line segment on the paper. You can be sure that the new position is different from the previous position for each instruction. At last, the Euler machine will always issue an instruction that move the pencil back to the starting position (X0, Y 0). In addition, the Euler machine will definitely not draw any lines that overlay other lines already drawn. However, the lines may intersect.

After all the instructions are issued, there will be a nice picture on Joey’s paper. You see, since the

pencil is never lifted from the paper, the picture can be viewed as an Euler circuit.

Your job is to count how many pieces (connected areas) are created on the paper by those lines

drawn by Euler.



Input

There are no more than 25 test cases. Ease case starts with a line containing an integer N ≥ 4, which

is the number of instructions in the test case. The following N pairs of integers give the instructions

and appear on a single line separated by single spaces. The first pair is the first instruction that gives

the coordinates of the starting position. You may assume there are no more than 300 instructions in

each test case, and all the integer coordinates are in the range (-300, 300). The input is terminated

when N is 0.

Output

For each test case there will be one output line in the format

Case x: There are w pieces.,

where x is the serial number starting from 1.

Note: The figures below illustrate the two sample input cases.

Sample Input

5

0 0 0 1 1 1 1 0 0 0

7

1 1 1 5 2 1 2 5 5 1 3 5 1 1

0

Sample Output

Case 1: There are 2 pieces.

Case 2: There are 5 pieces.

题意:给你一个闭合的曲线,计算这个曲线有多少个平面。

分析:如果直接找所有的区域会比较的麻烦,但是可以利用欧拉定理来进行计算。

欧拉定理:设平面的顶点数,边数,面数为V,E,F,则V+F-E = 2,即F = E+2-V。

所以我们只要求出顶点数和边数就可以求出面数。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>

using namespace std;

const double eps = 1e-6;

const double PI = acos(-1.0);

//################################################################### 二维几何

typedef struct Point
{
double x,y;

Point(double x= 0 ,double y = 0 ):x(x),y(y){}

Point operator + (const Point &a)const {return Point(a.x+x,y+a.y);}

Point operator - (const Point &a)const {return Point(x-a.x,y-a.y);}

Point operator * (const double &a)const {return Point(x*a,y*a);}

Point operator / (const double &a)const {return Point(x/a,y/a);}

bool operator < (const Point &a)const {return x<a.x||(x==a.x&&y<a.y);}

}Vector;

int dbcmp(double x)
{
if(fabs(x)<eps) return 0;

return x>0?1:-1;
}

bool operator == (const Point &a,const Point  b) //判断点的相等
{
return dbcmp(a.x-b.x)==0 && dbcmp(a.y-b.y)==0;
}

double Dot(Vector A,Vector B) {return A.x*B.x+A.y*B.y;} //点积

double Cross(Vector A,Vector B) {return A.x*B.y-A.y*B.x;} //叉积

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 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));} //二维向量逆时针旋转rad

Point GetLineIntersection(Point P,Vector v,Point Q,Point w) //求两直线Pv,Qw交点,保证直线只有唯一的一个交点。
{
Vector u = P-Q;

double t = Cross(w,u)/Cross(v,w);

return P+v*t;
}

double DistanceToLine(Point P,Point A,Point B) //点P到直线AB的距离
{
Vector v1 = B-A,v2 = P - A;

return fabs(Cross(v1,v2)/Length(v1));
}

double DistanceToSegment(Point P,Point A,Point B) //点到线段的最短距离
{
if(A == B) return Length(P-A);

Vector v1 = B - A,v2 = P-A,v3 = P-B;

if(dbcmp(Dot(v1,v2))<0) return Length(v2);//在A端点的外面

else if(dbcmp(Dot(v1,v3))>0) return Length(v3);//在B端点的外面

else return fabs(Cross(v1,v2)/Length(v1));
}

Point GetLineProjection(Point P,Point A,Point B) //点在线段上的投影的坐标
{
Vector v = B-A;

return A+v*(Dot(v,P-A)/Dot(v,v));
}

bool SegmentProperIntersection(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 dbcmp(c1)*dbcmp(c2)<0&&dbcmp(c3)*dbcmp(c4)<0;
}

bool OnSegment(Point P,Point A,Point B) { return dbcmp(Cross(A-P,B-P)) == 0 && dbcmp(Dot(A-P,B-P)) < 0;} //判断点P是不是在线段AB上

double PolygonArea(Point *p,int n)//求多边形的有向面积
{
double Area = 0;

for(int i = 1;i < n-1; i++) Area += Cross(p[i]-p[0],p[i+1]-p[0]);

return Area/2;
}

Point GetMorley(Point A,Point B,Point C)//Morley定理
{
Vector v1  = C-B;

double a1 = Angle(A-B,v1);

v1 = Rotate(v1,a1/3);

Vector v2 = B-C;

double a2 = Angle(A-C,v2);

v2 = Rotate(v2,-a2/3);

return GetLineIntersection(B,v1,C,v2);
}

int n;

Point P[400];

Vector V[400*400];

int main()
{
int num ;

int z = 1;

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--;
num = 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[num++] = GetLineIntersection(P[i],P[i+1]-P[i],P[j],P[j+1]-P[j]);
}
}
}

sort(V,V+num);

int ans = n;

num = unique(V,V+num)-V;//由于存在共点的情况,所以要去重。
for(int i = 0 ;i<num;i++)//根据点是不是在线段上,判断边的数量。
{
for(int j = 0;j<n;j++)
{
if(OnSegment(V[i],P[j],P[j+1]))
{
ans++;
}
}
}

printf("Case %d: There are %d pieces.\n",z++,ans+2-num);//根据欧拉定理求解。

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: