题目链接: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;
}