zoj 1010
View Code
1 #include <iostream> 2 #include <cmath> 3 using namespace std; 4 5 // 精度容差 6 const double EPS = 1e-5; 7 8 // 允许容差的浮点数相等 9 inline bool equals( double x, double y ) { 10 return fabs( x - y ) < EPS; 11 } 12 13 // 点结构 14 struct Point { 15 Point() {} 16 Point( double x, double y ) : posX( x ), posY( y ) {} 17 void getPoint() { cin >> posX >> posY; } 18 double posX, posY; 19 }; 20 21 // 判断两点是否重合 22 bool cover( Point pointA, Point pointB ) { 23 return fabs( pointA.posX - pointB.posX ) + 24 fabs( pointA.posY - pointB.posY ) < EPS; 25 } 26 27 // 线段类 28 class LineSegment { 29 public: 30 LineSegment() {} 31 // 构造函数,两点一线 32 LineSegment( Point pA, Point pB ) : pointA( pA ), pointB( pB ) {} 33 // 判别点在线的哪一侧,返回值为叉积 34 double pointOnItsSide( Point ); 35 // 判别点是否在线上 36 bool pointOnLine( Point ); 37 // 判别两线是否相交 38 friend bool cross( LineSegment, LineSegment ); 39 private: 40 Point pointA, pointB; 41 }; 42 43 double LineSegment :: pointOnItsSide( Point point ) { 44 return ( point.posX - pointA.posX ) * ( pointB.posY - pointA.posY ) - 45 ( point.posY - pointA.posY ) * ( pointB.posX - pointA.posX ); 46 } 47 48 bool LineSegment :: pointOnLine( Point point ) { 49 // 若端点重合,必定相交 50 if( cover( point, pointA ) || cover( point, pointB ) ) return true; 51 // 若点在线段坐标顶点方框外,必定不相交 52 if( point.posX > pointA.posX && point.posX > pointB.posX || 53 point.posX < pointA.posX && point.posX < pointB.posX || 54 point.posY > pointA.posY && point.posY > pointB.posY || 55 point.posY < pointA.posY && point.posY < pointB.posY ) return false; 56 // 否则,点必定不在延长线或端点上,只要点与直线叉积非零即不在线上 57 return equals( pointOnItsSide( point ), 0.0 ); 58 } 59 60 bool cross( LineSegment lineA, LineSegment lineB ) { 61 // 若一条直线端点在另一直线上,必然相交 62 if( lineA.pointOnLine( lineB.pointA ) || lineA.pointOnLine( lineB.pointB ) || 63 lineB.pointOnLine( lineA.pointA ) || lineB.pointOnLine( lineA.pointB ) ) return true; 64 double prod11 = lineA.pointOnItsSide( lineB.pointA ), 65 prod12 = lineA.pointOnItsSide( lineB.pointB ), 66 prod21 = lineB.pointOnItsSide( lineA.pointA ), 67 prod22 = lineB.pointOnItsSide( lineA.pointB ); 68 return prod11 * prod12 < -EPS && prod21 * prod22 < -EPS; 69 } 70 71 // 多边形类 72 class Polygon { 73 public: 74 Polygon() {} 75 int getPolygon(); 76 bool isValid(); 77 double area(); 78 private: 79 int size; 80 Point vertex[1000]; 81 LineSegment edge[1000]; 82 }; 83 84 int Polygon :: getPolygon() { 85 cin >> size; 86 int i = 0; 87 for( i = 0; i < size; i++ ) 88 vertex[i].getPoint(); 89 for( i = 1; i < size; i++ ) 90 edge[i] = LineSegment( vertex[i - 1], vertex[i] ); 91 edge[0] = LineSegment( vertex[size - 1], vertex[0] ); 92 return size; 93 } 94 95 bool Polygon :: isValid() { 96 if( size < 3 ) 97 return false; 98 if( size == 3 ) 99 return !fabs( LineSegment( vertex[0], vertex[1] ).pointOnItsSide( vertex[2] ) ) < EPS; 100 for( int j = 2; j < size - 1; j++ ) 101 if( cross( edge[0], edge[j] ) ) return false; 102 for( int i = 1; i < size - 2; i++ ) 103 for( int j = i + 2; j < size; j++ ) 104 if( cross( edge[i], edge[j] ) ) 105 return false; 106 return true; 107 } 108 109 double Polygon :: area() { 110 double ans = 0.0; 111 if( size < 3 ) return ans; 112 for( int i = 2; i < size; i++ ) 113 ans += edge[i].pointOnItsSide( vertex[0] ); 114 return fabs( ans / 2.0 ); 115 } 116 117 int main() 118 { 119 Polygon Pattern; 120 int T = 1; 121 cout.setf( ios :: fixed ); 122 cout.precision( 2 ); 123 while( Pattern.getPolygon() ) { 124 if( T != 1 ) cout << endl; 125 cout << "Figure " << T++ << ": "; 126 if( !Pattern.isValid() ) 127 cout << "Impossible" << endl; 128 else cout << Pattern.area() << endl; 129 } 130 return 0; 131 }
代码一用c++的风格,代码二用c风格。
View Code 2
1 #include<stdio.h> 2 #define max(a,b) ((a)>(b)?(a):(b)) 3 #define min(a,b) ((a)<(b)?(a):(b)) 4 double x[1000],y[1000]; 5 6 //叉积,p0p1 X p0p2,>0 p0p2沿着p0右旋得到p0p1,<0 左旋得到,=0 共线 7 double multi(int p1,int p2,int p0) 8 { 9 return (x[p1]-x[p0])*(y[p2]-y[p0])-(x[p2]-x[p0])*(y[p1]-y[p0]); 10 } 11 int isIntersected(int s1,int e1,int s2,int e2)//线段s1e1与s2e2是否相交 12 { 13 if(max(x[s1],x[e1])<min(x[s2],x[e2])) 14 return 0; 15 if(max(x[s2],x[e2])<min(x[s1],x[e1])) 16 return 0; 17 if(max(y[s1],y[e1])<min(y[s2],y[e2])) 18 return 0; 19 if(max(y[s2],y[e2])<min(y[s1],y[e1])) 20 return 0; 21 if(multi(s2,e1,s1)*multi(e1,e2,s1)<0) 22 return 0; 23 if(multi(s1,e2,s2)*multi(e2,e1,s2)<0) 24 return 0; 25 return 1; 26 } 27 double polygonArea(int n)//计算多边形面积,凹凸多边形皆可 28 { 29 double area=0; 30 int i; 31 for(i=1;i<n;i++) 32 area+=x[i-1]*y[i]-x[i]*y[i-1]; 33 area+=x[n-1]*y[0]-x[0]*y[n-1]; 34 if(area<0) // 得到的是有向面积,取绝对值 35 area*=-1; 36 return area/2; 37 } 38 int main() 39 { 40 freopen("in.txt","r",stdin); 41 int n,caseNum=0,i,j; 42 double area=0; 43 begin: while(scanf("%d",&n)&&n) 44 { 45 caseNum++; 46 if(caseNum>1) 47 printf("\n"); 48 for(i=0;i<n;i++) 49 scanf("%lf %lf",&x[i],&y[i]); 50 if(n<3) //小于三个点不可能组成多边形 51 { 52 printf("Figure %d: Impossible\n",caseNum); 53 continue; 54 } 55 for(i=1;i<=n-1;i++) //判断能否组成多边形 56 { 57 for(j=1;j<=i-2;j++) 58 if(isIntersected(i-1,i,j-1,j)) 59 { 60 printf("Figure %d: Impossible\n",caseNum); 61 goto begin; 62 } 63 } 64 for(i=2;i<n-1;i++) 65 if(isIntersected(n-1,0,i-1,i)) 66 { 67 printf("Figure %d: Impossible\n",caseNum); 68 goto begin; 69 } 70 //计算多边形面积 71 printf("Figure %d: %.2lf\n",caseNum,polygonArea(n)); 72 } 73 return 0; 74 }