最基本的概念就是叉积,其实说白了就是三角形的面积的2倍。但是叉积有正负,所以可以用来判定给定的三个点的顺序问题。
叉积的公式为:E X C = x1*y2 - x2*y1(在原点的情况)。模板为:
double multi(point p0,point p1,point p2)//计算叉积
{ return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
(1) 若C×E<0,则E在C的顺时针方向;(2)若C×E>0,则E在C的逆时针方向;(3)若C×E=0,则E与C共线,但可能同向也可能反向。
上面的图形中要求三角形OCE的面积S,因为:2S=2*(矩形OABD的面积-S1-S2-S3),所以S=|x1y2-x2y1|/2。
用这种方法可以求一般的三角形面积,模板为:
struct Point
{ double x,y;
};
Point P[3];
double Area()
{ return fabs(P[0].x*P[1].y+P[1].x*P[2].y+P[2].x*P[0].y-P[1].x*P[0].y-P[2].x*P[1].y-P[0].x*P[2].y)/2;
}
这个就是上面叉积化简得到的,只是利用叉积的时候要加绝对值和/2。
同样我们可以用三角形面积求多边形面积,可以拆分成多个小三角形面积之和,如图所示:
四边形ABCD的面积可以分解为三角形PAB的面积+PBC+PCD+PDA(P为四边形内任意一点),由于都是顺时针方向,所以利用叉积求出三角形面积后取绝对值刚好是四边形面积。
但是P(x,y)为任意一点的话,这个时候求面积就有些复杂了,比方说A(x1,y1),B(x2,y2)。那么三角形PAB的面积=|(x1-x)*(y2-y)-(x2-x)*(y1-y)|;那么如果这个点为原点的话就很简单了,这个时候PAB的面积=|x1*y2-x2*y1|。问题是P点为原点求出来的面积是不是等于四边形的面积呢?
我们可以看到三角形OAB,OBC,OCD,三点的顺序都是顺时针的,三者的叉积值的符号都是相同的,加起来后的绝对值面积为OABCD的面积,当运行到D点时,三角形ODA三点的顺序是逆时针,刚好与前面的三个三角形的结果值相反,所以OABCD的面积-ODA的面积=ABCD的面积。所以直接以原点为顶点,运用叉积求出即为多边形的面积。
模板为:
const int MAX=1010;
typedef point polygon[MAX];
double polygon_area(polygon p,int n)
{ double area=0.0;
for(int i=1;i<=n;i++)
area+=p[i-1].x*p[i%n].y-p[i%n].x*p[i-1].y; //以原点为定点
return fabs(area)/2;
}
利用叉积求三个点的顺序NYOJ 68(三点顺序):
#include<iostream>
using namespace std;
struct Point
{ int x,y;
friend istream& operator>>(istream &cin,Point &P)
{ cin>>P.x>>P.y;
return cin;
}
bool operator==(const int &n) const
{ return x==n&&y==n;
}
};
Point P[10];
double multi()
{ return (P[1].x-P[0].x)*(P[2].y-P[0].y)-(P[2].x-P[0].x)*(P[1].y-P[0].y);
}
int main()
{ while(cin>>P[0]>>P[1]>>P[2])
{ if(P[0]==0&&P[1]==0&&P[2]==0) break;
if(multi()>0) cout<<0<<endl;
else cout<<1<<endl;
}
return 0;
}
2、Pick定理:给定顶点坐标均是整点的简单多边形,那么其面积A和内部格点数目i,边上格点数目b的关系:A=i+b/2 - 1。
求线段上的整点的个数:
给定点P(x0,y0)和Q(x1,y1),若某一个点A(x,y)在这条线段上,那么由定比分点公式有x=x0+λ(x1-x0),y=y0+λ(y1-y0)。由于是整点,所以λ一定为分数,且是(x1-x0)和(y1-y0)的公因数,所以这条线上整点的个数为(x1-x0)和(y1-y0)的最大公约数,sum=gcd(dx,dy)=gcd(x1-x0,y1-y0)。具体模板见代码,注意面积用__int64型:
#include<iostream>
#include<cstdlib>
using namespace std;
#define __int64 long long
struct Point
{ int x,y;
friend istream& operator>>(istream& cin,Point &P)
{ cin>>P.x>>P.y;
return cin;
}
bool operator==(const int &n) const
{ return x==n&&y==n;
}
};
Point P[10];
int gcd(int n,int m)
{ return m==0?n:gcd(m,n%m);
}
__int64 Area(int n) //求多边形面积
{ __int64 area=0;
for(int i=1;i<=n;i++)
area+=P[i-1].x*P[i%n].y-P[i%n].x*P[i-1].y;
return abs(area);
}
int Count(int n) //求在线段的点的个数和
{ int sum=0;
for(int i=1;i<=n;i++)
{ int dx=abs(P[i%n].x-P[i-1].x);
int dy=abs(P[i%n].y-P[i-1].y);
sum+=gcd(dx,dy);
}
return sum;
}
int main()
{ while(cin>>P[0]>>P[1]>>P[2])
{ if(P[0]==0&&P[1]==0&&P[2]==0) break;
__int64 area=Area(3);
int I=(area-Count(3))/2+1;
cout<<I<<endl;
}
return 0;
}