欧拉定理:
简单多面体的顶点数V、棱数E及面数F间有关系有著名的欧拉公式:V-E+F=2。
设G为任意的连通的平面图,则v-e+f=2,v是G的顶点数,e是G的边数,f是G的面数。(引)
这题的做法就是模拟画线的过程,统计出画每一条线时与之前所有线的交点,将所有交点记录下来,将每一个顶点也记录下来。然后将点去重,得到点数。然后统计每一条线上有几个点,那么这条线就被分成了点数+1段,这样得到边数。最后根据公式算出面数。
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 using namespace std; 5 namespace X 6 { 7 const double eps=1e-10; 8 struct Point 9 { 10 double x,y; 11 Point(double x=0,double y=0):x(x),y(y){} 12 }; 13 typedef Point Vec; 14 Vec operator+(const Vec& a,const Vec& b) 15 { 16 return Vec(a.x+b.x,a.y+b.y); 17 } 18 Vec operator-(const Vec& a,const Vec& b) 19 { 20 return Vec(a.x-b.x,a.y-b.y); 21 } 22 Vec operator*(const double& a,const Vec& b) 23 { 24 return Vec(a*b.x,a*b.y); 25 } 26 Vec operator*(const Vec& a,const double& b) 27 { 28 return Vec(b*a.x,b*a.y); 29 } 30 Vec operator/(const Vec& a,const double& b) 31 { 32 return Vec(a.x/b,a.y/b); 33 } 34 int dcmp(double x) 35 //正为1,负为-1,0为0 36 { 37 if(fabs(x)<eps) return 0; 38 return x<0?-1:1; 39 } 40 bool operator<(const Vec& a,const Vec& b) 41 //人为规定的优先级 42 { 43 return a.x<b.x||(a.x==b.x&&a.y<b.y); 44 } 45 bool operator==(const Vec& a,const Vec& b) 46 //判向量相等 47 { 48 return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; 49 } 50 double dot(const Vec& a,const Vec& b) 51 //点积 52 { 53 return a.x*b.x+a.y*b.y; 54 } 55 double cross(const Vec& a,const Vec& b) 56 //叉积 57 { 58 return a.x*b.y-a.y*b.x; 59 } 60 double len(const Vec& x) 61 //向量长度 62 { 63 return sqrt(dot(x,x)); 64 } 65 double angle(const Vec& a,const Vec& b) 66 //夹角,0~180° 67 { 68 return acos(dot(a,b)/len(a)/len(b)); 69 } 70 double angle1(const Vec& a,const Vec& b) 71 //夹角,带方向,a到b逆时针为正,顺时针为负,共线为0 72 { 73 return acos(dot(a,b)/len(a)/len(b))*(dcmp(cross(a,b))); 74 } 75 Vec rotate(const Vec& a,const double& rad) 76 //旋转,正为逆时针,负为顺时针 77 { 78 return Vec(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad)); 79 } 80 Vec normal(const Vec& x) 81 //单位法线,左转90°后除以自身长度 82 { 83 double l=len(x); 84 return Vec(-x.y/l,x.x/l); 85 } 86 Vec normal1(const Vec& x) 87 //法线,不归一化 88 { 89 return Vec(-x.y,x.x); 90 } 91 Point lineline(const Point& p,const Vec& v,const Point& q,const Vec& w) 92 //直线交点,GetLineIntersection 93 { 94 return p+v*cross(w,p-q)/cross(v,w); 95 } 96 double ptline(const Point& p,const Point& a,const Point& b) 97 //point_to_line,点到直线距离,DistanceToLine 98 { 99 Vec v1=b-a,v2=p-a; 100 return fabs(cross(v1,v2)/len(v1)); 101 } 102 double ptseg(const Point& p,const Point& a,const Point& b) 103 //point_to_segment,点到线段距离,DistanceToSegment 104 { 105 if(a==b) return len(p-a); 106 //Vec v1=b-a,v2=a-p,v3=p-b; 107 Vec v1=b-a,v2=p-a,v3=p-b; 108 if(dcmp(dot(v1,v2))<0) return len(v2); 109 else if(dcmp(dot(v1,v3))>0) return len(v3); 110 else return fabs(cross(v1,v2)/len(v1)); 111 } 112 double area2(const Point& a,const Point& b,const Point& c) 113 //叉积对应平行四边形的面积 114 { 115 return cross(b-a,c-a); 116 } 117 double thrarea(const Point& a,const Point& b,const Point& c) 118 //三角形面积,绝对值 119 { 120 return fabs(cross(b-a,c-a)/2); 121 } 122 bool ifpar(const Vec& a,const Vec& b) 123 //ifParallel 124 //是否共线/平行 125 { 126 return dcmp(cross(a,b))==0; 127 } 128 Point pointline(const Point& p,const Point& a,const Vec& v) 129 //点在直线上投影,GetLineProjection 130 { 131 return a+v*(dot(p-a,v)/dot(v,v)); 132 } 133 bool ifsegseg(const Point& a1,const Point& a2,const Point& b1,const Point& b2) 134 //SegmentProperIntersection,线段相交判定,不包含端点,不允许共线。有交点时求交点直接用直线交点即可 135 //此处就是求两条线段的两个端点是否都分别在另一条线段的两侧 136 { 137 double c1=cross(a2-a1,b1-a1),c2=cross(a2-a1,b2-a1), 138 c3=cross(b2-b1,a1-b1),c4=cross(b2-b1,a2-b1); 139 return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0; 140 } 141 bool ifonseg(const Point& p,const Point& a1,const Point& a2) 142 //OnSegment,点是否在线段上 143 //这样就能判定向量p a1与p a2共线,且方向相反 144 { 145 return dcmp(cross(a1-p,a2-p))==0&&dcmp(dot(a1-p,a2-p))<0; 146 } 147 bool ifsegseg1(const Point& a1,const Point& a2,const Point& b1,const Point& b2) 148 //线段相交判定,包含端点,允许共线 149 { 150 double c1=cross(a2-a1,b1-a1),c2=cross(a2-a1,b2-a1), 151 c3=cross(b2-b1,a1-b1),c4=cross(b2-b1,a2-b1); 152 return (dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0)|| 153 (dcmp(c1)==0&&dcmp(c2)==0)||ifonseg(a1,b1,b2)|| 154 ifonseg(a2,b1,b2)||ifonseg(b1,a1,a2)||ifonseg(b2,a1,a2); 155 } 156 double polyarea(Point p[],int n) 157 //PolygonArea,有向面积,要求点按顺序能组成多边形(不会边相交,可以凹),如果顺时针转就是负,逆时针就是正(未验证) 158 { 159 double ans=0; 160 for(int i=1;i<n-1;i++) 161 ans+=cross(p[i]-p[0],p[i+1]-p[0]); 162 return ans/2; 163 } 164 }; 165 using namespace X; 166 Point p[310]; 167 Point p2[100000]; 168 int n,v,e,T; 169 int main() 170 { 171 int i,j; 172 scanf("%d",&n); 173 while(n!=0) 174 { 175 v=0;e=n-1; 176 scanf("%lf%lf",&p[1].x,&p[1].y); 177 p2[++v]=p[1]; 178 for(i=2;i<=n;i++) 179 { 180 scanf("%lf%lf",&p[i].x,&p[i].y);p2[++v]=p[i]; 181 for(j=1;j<=i-2;j++) 182 { 183 if(ifsegseg(p[i-1],p[i],p[j],p[j+1])) 184 p2[++v]=lineline(p[i-1],p[i]-p[i-1],p[j],p[j+1]-p[j]); 185 } 186 } 187 sort(p2+1,p2+v+1); 188 v=unique(p2+1,p2+v+1)-p2-1; 189 for(i=1;i<n;i++) 190 for(j=1;j<=v;j++) 191 if(ifonseg(p2[j],p[i],p[i+1])) 192 e++; 193 printf("Case %d: There are %d pieces. ",++T,e+2-v); 194 scanf("%d",&n); 195 } 196 return 0; 197 }