题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1010
每次做几何题总能学到新东西,而且永远也学不完,并且学完以后从来没用过。
(向量 a=(x1, y1),向量 b=(x2, y2),向量c=(x3, y3),向量d=(x4,y4))
叉乘和点乘:
叉乘:a × b = x1 * y2 - x2 * y1;
点乘:a * b = x1 * x2 + y1 * y2。
其中叉乘的结果的绝对值是三角形面积的两倍(叉乘的结果是三角形有向面积的两倍),结果等于0,向量共线;大于0,b在a的逆时针方向;小于0,b在a的顺时针方向。
判断边ab与cd相交:
判断点a,b,c有重合的点:
计算面积:
A = 0.5 * (p0 × p1 + p1 ×p2 +...+ p(n-1) × pn) (公式适用于凸多边形和凹多边形,p是点的编号,p0和pn是同一个点,把点坐标当做向量坐标来求叉积)。
#include<iostream> #include<cstdio> #include<cmath> #define eps 1e-8 using namespace std; double x[1010], y[1010]; double area(int n, double x[], double y[]) { int i; double ans = 0; for (i=1; i<=n; i++) ans += x[i-1] * y[i] - y[i-1] * x[i]; return fabs(ans / 2); } double cross(int a, int b, int c) { return (x[b] - x[a]) * (y[c] - y[a]) - (x[c] - x[a]) * (y[b] - y[a]); } double dot(int a, int b, int c) { return (x[b] - x[a]) * (x[c] - x[a]) + (y[b] - y[a]) * (y[c] - y[a]); } int compare(double d) { if (fabs(d) < eps) return 0; return d > 0 ? 1 : -1; } int between(int a, int b, int c) { return compare(dot(a, b, c)); } int intersect(int s, int t) { int d1 = compare(cross(s, s+1, t)); int d2 = compare(cross(s, s+1, t+1)); int d3 = compare(cross(t, t+1, s)); int d4 = compare(cross(t, t+1, s+1)); if (d1 * d2 < 0 && d3 * d4 < 0) return 1; if (d1 == 0 && between(s, s+1, t) == 0 || d2 == 0 && between(s, s+1, t+1) == 0 || d3 == 0 && between(t, t+1, s) == 0 || d4 == 0 && between(t, t+1, s+1) == 0) return 2; return 0; } int main() { int n; int iCase = 0; int i, j; while (scanf("%d",&n) && n) { for (i=1; i<=n; i++) cin>>x[i]>>y[i]; x[0] = x[n]; y[0] = y[n]; if (iCase) cout<<endl; printf("Figure %d: ",++iCase); int flag = 1; if (n < 3) flag = 0; for (i=n-3; i>=0 && flag; i--) for (j=i+2; j<n && flag; j++) { if (i == 0 && j == n-1) break; if (intersect(i, j)) flag = 0; } if (flag) printf("%.2lf\n",area(n, x, y)); else printf("Impossible\n"); } return 0; }