人生第一道正儿八经的计算几何题。。。光消编译错误就弄了老半天,果然是够弱。。
题意大概是,给你N条线段,它们会构成一个一笔画的图形,给你先线段的顺序就是一笔画的顺序,线段可能相交但是不会重合
问你最后那个图形可以将平面分成多少个区域(包括有穷区域和无穷区域)
显然这里可以利用欧拉定理来求解,即平面上的点数+面数=边数+2
那么问题就转化为求最后的图形有多少个点和多少条边了。
大体思路是,通过枚举线段来求出所有线段的交点,加上原有题目告诉你的所有线段的起点和终点,可以求得图中所有的点的数量。
但是因为有可能出现三点共线的情况,这样会导致多余的点的出现,因此求出所有的点之后对点集做一次去重处理,可以利用STL里面的unique函数,非常的方便
然后枚举每一个新增的交点,如果这个交点在一个线段之间,那么就会导致一条新边的产生。
由此就完成了边和点的统计
#include <cstdio> #include <algorithm> #include <cmath> #define INPUT_FILE "in.txt" #define OUTPUT_FILE "out.txt" using namespace std; typedef long long LL; const int maxn = 400; const double eps = 1e-10; void setfile() { freopen(INPUT_FILE,"r",stdin); freopen(OUTPUT_FILE,"w",stdout); } struct Point { double x,y; Point(double x = 0,double y = 0):x(x),y(y) { } }; typedef Point Vector; Point v[maxn * maxn]; //顶点 Point p[maxn]; 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); } Vector operator + (Vector a,Vector b) { return Vector(a.x + b.x,a.y + b.y); } double dot(Vector a,Vector b) { return a.x * b.x + a.y * b.y; } int dcmp(double x) { if(fabs(x) < eps) return 0; return x < 0 ? -1 : 1; } bool operator < (Point a,Point b) { return a.x < b.x || (a.x == b.x && a.y < b.y); } double cross(Vector a,Vector b) { return a.x * b.y - a.y * b.x; } bool have_intersection(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); bool ret = (dcmp(c1) * dcmp(c2) < 0) && (dcmp(c3) * dcmp(c4) < 0); return ret; } bool on_segment(Point p,Point a,Point b) { return dcmp(cross(p - a,p - b)) == 0 && dcmp(dot(a - p,b - p)) < 0; } Point get_intersection(Point a1,Point a2,Point b1,Point b2) { Vector v = a2 - a1,w = b2 - b1,u = a1 - b1; double t = cross(w,u) / cross(v,w); return a1 + v * t; } bool operator == (Point a,Point b) { return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0; } int main() { int n,kase = 1; while(scanf("%d",&n),n) { for(int i = 0;i < n;i++) { scanf("%lf%lf",&v[i].x,&v[i].y); p[i] = v[i]; } int cnt_v = n - 1,cnt_f = 0,cnt_e = n - 1; n--; //判断一下给定的线段是否有交点 for(int i = 0;i < n;i++) { for(int j = i + 1;j < n;j++) { if(have_intersection(p[i],p[i + 1],p[j],p[j + 1])) { //找到交点了就添加到点集里面 v[cnt_v++] = get_intersection(p[i],p[i + 1],p[j],p[j + 1]); } } } //特判三点共线的时候的状态 sort(v,v + cnt_v); cnt_v = unique(v,v + cnt_v) - v; //处理因为线段交点而新生成的线段 for(int i = 0;i < cnt_v;i++) { for(int j = 0;j < n;j++) { if(on_segment(v[i],p[j],p[j + 1])) { cnt_e++; } } } printf("Case %d: There are %d pieces. ",kase++,2 + cnt_e - cnt_v); } return 0; }