题目大意:
n个端点的一笔画 第n个和第1个重合 即一笔画必定是闭合曲线
输出平面被分成的区域数
欧拉定理 V+F-E=2 即 点数+面数-边数=2 (这里的面数包括了外部)
#include <bits/stdc++.h> using namespace std; const double eps=1e-10; double add(double a,double b) { if(abs(a+b)<eps*(abs(a)+abs(b))) return 0; return a+b; } struct P { double x,y; P(){} P(double _x,double _y):x(_x),y(_y){} P operator - (P p) { return P(add(x,-p.x),add(y,-p.y)); } P operator + (P p) { return P(add(x,p.x),add(y,p.y)); } P operator / (double d) { return P(x/d,y/d); } P operator * (double d) { return P(x*d,y*d); } double dot (P p) { return add(x*p.x,y*p.y); } double det (P p) { return add(x*p.y,-y*p.x); } bool operator <(const P& p)const { return x<p.x || (x==p.x && y<p.y); } bool operator ==(const P& p)const { return abs(x-p.x)<eps && abs(y-p.y)<eps; } void read(){ scanf("%lf%lf",&x,&y); } }p[305], v[305*305], t; int n; bool onSeg(P a,P b,P c) { return (a-c).det(b-c)==0 && (a-c).dot(b-c)<=0; } /// c是否在线段ab上 包括端点 bool onSeg2(P a,P b,P c) { return (a-c).det(b-c)==0 && (a-c).dot(b-c)<0; } /// c是否在线段ab上 不包括端点 P ins(P a,P b,P c,P d) { return a+(b-a)*((d-c).det(c-a)/(d-c).det(b-a)); } /// 直线ab与cd的交点 bool insSS(P a,P b,P c,P d) { if((a-b).det(c-d)==0) { // 平行 return onSeg(a,b,c) || onSeg(a,b,d) || onSeg(c,d,a) || onSeg(c,d,b); } else { t=ins(a,b,c,d); return onSeg(a,b,t) && onSeg(c,d,t); } } /// 线段ab与cd是否相交 int main() { int o=1; while(~scanf("%d",&n)) { if(n==0) break; for(int i=0;i<n;i++) p[i].read(), v[i]=p[i]; n--; // 最后一个和第一个重合 int c=n, e=n; for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) if(insSS(p[i],p[i+1],p[j],p[j+1])) v[c++]=t; /// 若相交 加入交点 sort(v,v+c); // 排序需重载< c=unique(v,v+c)-v; // 去重需重载== for(int i=0;i<c;i++) for(int j=0;j<n;j++) if(onSeg2(p[j],p[j+1],v[i])) e++; /// 线段上一个非端点的点可以把一条线段分成两段 printf("Case %d: There are %d pieces. ",o++,e+2-c); } return 0; } //21860