1. 叉乘:
若 ,,则
而
则
为三角形面积,建议百度叉乘的几何意义
2. 皮克公式:
即:多边形面积S = 多边形内整数点的个数 n + 多边形边上整数点的个数 / 2 - 1
3. 线段上整数点的个数:
GCD(线段在X轴的投影长,线段在Y轴的投影长) + 1
4. 任意多边形的面积
上文给出了三角形的公式,对于只给出了顶点的情况下,我们不能直接利用皮克公式,而可以将n边形化成 n-2 个三角形
,依次用叉乘算出每个三角形的面积,求和就得到了多边形的面积,计算时用到了的边向量,于是化简可以得到多边形的面积公式(点的坐标必须是顺时针或逆时针依次给出的):
读者可能会想如果点的坐标不是按顺序依次给出的又该怎么办呢?
(1)所给多边形为凹包:
如果点不是按照顺序依次给出的,那么所构成的多边形一定不唯一(画画就明了),所以点一定是按顺序给出的
(2)所给多边形为凸包:
我们可以先将点按极角排序,就可套用公式了,(凹包的点极角排序后多边形的顶点不是依次有序的)
ps:极角排序
ps:线性代数知识解释公式来历
5. 应用:
题意:
给你三个点,求三个点组成的三角形内有多少个整数点,不算边上的,也就是求皮克公式中的n
代码:
// n = S - s/2 + 1
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long double ld;
int main()
{
int x1,y1,x2,y2,x3,y3;
while(cin>>x1>>y1>>x2>>y2>>x3>>y3)
{
if(x1==0&&y1==0&&x2==0&&y2==0&&x3==0&&y3==0)
break;
int a1 = x2-x1,b1 = y2-y1;
int a2 = x3-x1,b2 = y3-y1;
int S = abs(a1*b2-b1*a2)/2; //要加绝对值
int s = __gcd(abs(x1-x2),abs(y1-y2))+1;
s += __gcd(abs(x3-x2),abs(y3-y2))+1;
s += __gcd(abs(x1-x3),abs(y1-y3))+1-3;//重复计算了3个顶点
cout<<S - s/2 + 1<<endl;
}
return 0;
}
代码:
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef long double ld;
int main()
{
int x1,y1,x2,y2,x3,y3;
while(cin>>x1)
{
if(x1==-1) break;
cin>>y1>>x2>>y2>>x3>>y3;
int a1 = x2-x1,b1 = y2-y1;
int a2 = x3-x1,b2 = y3-y1;
double S = abs((double)a1*b2-b1*a2)/2.0;
int ab = __gcd(abs(x1-x2),abs(y1-y2))+1;
int bc= __gcd(abs(x3-x2),abs(y3-y2))+1;
int ac= __gcd(abs(x1-x3),abs(y1-y3))+1;
int s = ab + bc + ac - 3;
printf("%.1f ",S);
printf("%lld %d %d %d\n",(ll)S-s/2+1,ab-2,bc-2,ac-2);
}
return 0;
}
(3) HDU 2036 多边形的面积
代码:
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
struct point
{
int x,y;
}p[150];
int main()
{
int n;
while(cin>>n&&n)
{
for(int i=0;i<n;++i)
cin>>p[i].x>>p[i].y;
int ans = p[n-1].x*p[0].y - p[n-1].y*p[0].x;
for(int i=0;i<n-1;++i)
ans += p[i].x*p[i+1].y - p[i].y*p[i+1].x;
printf("%.1f\n",abs(ans)*1.0/2.0);
}
return 0;
}
(4)牛客网-简单多边形
题意:
判断顶点坐标是按什么顺序给出的
题解:
根据叉乘的几何意义,顺时针计算,结果为负,逆时针结果为正
代码:
#include <cmath>
#include <iostream>
using namespace std;
int x[110];
int y[110];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;++i)
cin>>x[i]>>y[i];
int ans = 0;
for(int i=1;i<n;++i)
{
ans += x[i]*y[i+1] - x[i+1]*y[i];
}
ans += x[n]*y[1]-x[1]*y[n];
if(ans>0) cout<<"counterclockwise";
else cout<<"clockwise";
return 0;
}