您的位置:首页 > 其它

UVALive3263(计算几何基础)

2016-08-09 15:05 176 查看

好看的一笔画

依次按顺序给出一笔画所有顶点的坐标,求出平面中面的个数。

根据欧拉定理 V + F - E = 2 (V 是点,F是面,E是边),我们求出点数和边数就可以了。

通过判断线段相交,取得交点,然后经过去重处理得到所有的点。

然后枚举所有的点,如果点在线段上(不包括端点),那么这个线段被点分成了两部分,也就是边+1;

这样统计出来 边的个数, 点的个数 就求出面的个数了。 F = E + 2 - V;

感谢任学弟的精彩讲解

源代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include <algorithm>
#include<vector>
using namespace std;
const double eps = 1e-10;

int dcmp(double x){
if(fabs(x) < eps) return 0;
return x < 0 ? -1:1;
}
struct Point{
double x,y;
Point(double x = 0,double y = 0):x(x),y(y){}

bool operator <(const Point& b)const{
return x < b.x || (x == b.x && y < b.y);
}
bool operator == (const Point &b)const {
return dcmp(x - b.x) == 0&& dcmp(y - b.y) == 0;
}

};
typedef Point Vector ;
// 求向量 (x,y)的极角,atan2(y,x); -- C标准库
Vector operator + (Vector A,Vector B){
return Vector(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 * (Vector A,double p){
return Vector(A.x*p , A.y*p);
}
Vector operator / (Vector A,double p){
return Vector(A.x/p , A.y/p);
}

/*
bool operator < (const Point&a , const Point&b){

}
*/

double Dot(Point A,Point B) {return A.x*B.x+A.y*B.y;} //点积
double Cross(Point A,Point 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)); } //求出cos ,再用acos求出角度、

double Area2(Point A,Point B,Point C){ return Cross(B-A,C-A);}
//向量旋转 公式 x' = x * cosa - y * sina, y' = x * sina + y * cosa;
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); }
//计算交点, 调用前确保 Cross(v,w) 非0
//设 直线分别为 P + tv 和 Q + tw;
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;
}
//点到直线距离
double DistanceToLine(Point P, Point A,Point B){ //叉积 除以 底
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) ; // AB重合,成点对点长度
Vector v1 = B - A, v2 = P - A, v3 = P - B;
if(dcmp(Dot(v1,v2)) < 0) return Length(v2); // == 0 的时候是垂直的,小于零在二三象限; 即离A近;
else if(dcmp(Dot(v1,v2)) > 0) return Length(v3); //大于零 一四象限。
else return fabs(Cross(v1,v2)) / Length(v1); // 垂直的情况,直接用叉积来求了。
}
Point GetLineProjection(Point P,Point A,Point B){ //获得P在线段AB上投影的节点。
// AB向量 A + tv , Q 即投影点 A + t0v ,
// PQ 垂直于AB ,Dot()应该为0. 所以 Dot(v , P - (A + t0v))'
// 分配率 Dot(v , P - A) - t0 * Dot(v,v) = 0;
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) ;
double c3 = Cross(b2-b1 , a1 -b1) , 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 getD(Point A, Point B, Point C){ // A B C 逆时针给出
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);
}

Point read_Point(){
Point tmp;
scanf("%lf%lf",&tmp.x,&tmp.y);
return tmp;
}
vector<Point> G;
int main(){
int n;
Point po[333];
int cas = 0;
while(scanf("%d",&n)!=EOF && n){
G.clear();
for(int i=0;i<n;i++){
po[i] = read_Point();<span style="display: none; width: 0px; height: 0px;" id="transmark"></span>
G.push_back(po[i]);
}
// oula v-e+f=2 -> f = e + 2 - v;
n--; //
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(SegmentProperIntersection(po[i],po[i+1],po[j],po[j+1])){
G.push_back(GetLineIntersection(po[i],po[i+1]-po[i],po[j],po[j+1]-po[j]));
}
}
}
sort(G.begin(),G.end());
int c = unique(G.begin(),G.end()) - G.begin();
int e = n;
for(int i=0;i<c;i++){
for(int j=0;j<n;j++){
if(OnSegment(G[i],po[j],po[j+1])){
e++;
}
}
}
printf("Case %d: There are %d pieces.\n",++cas,e+2-c);

}
return 0 ;
}

/*
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

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