( 算法树之几何 )【 皮克定理 】
皮克定理是有关格点多边形的面积计算问题,因此在了解皮克定理前,我们要先看一下什么是格点多边形:
一、格点多边形
如图,每个小正方形的边长是1,图中的小正方形的顶点称为"格点",如果一个多边形的每个顶点都在格点上,则称该多边形为"格点多边形",如下图所示是格点四边形。
1899年,奥地利数学家乔治亚历山大匹克对格点多边形面积计算问题给出了以下公式:格点多边形面积=内点数+边界点数÷2-1,如果用m表示内点数,n表示边界点数即:S=m+n÷2-1
这个结论我们称作匹克定理。用它来计算格点多边形方便多了。
这么求边界点数?
1、对于两端点(x1,y1),(x2,y2)都再格点上的一条线段,该线段上的格点数目为gcd( |x1-x2|,|y1-y2| )+ 1,这很好理解,对于横坐标差值和纵坐标差值求得的最大公因数g,相当于将横坐标差值分成g份,由于是整除,因此显然每份的左右端点都是整数,对于纵坐标也是同样的道理,由于是最大公因数,所以不可能再分更多份,因此gcd( |x1-x2|,|y1-y2| )
即求得两端点间最多能分成多少段由格点分割的线段,再加上1即整条线段上的格点数目。
例题1:Gym 101873G
题意:按照顺时针给出n个点,点的坐标为整数,求n个点围成的凸多边形内部有几个点xy都是整数。
思路:就是求内点数,多边形面积可以求出,边界点数也可以求出。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
int x[200002],y[200002];
int n;
signed main()
{
cin >> n;
for ( int i=0; i<n; i++ ) scanf("%lld %lld",&x[i],&y[i]);
x[n]=x[0]; y[n]=y[0];
int sum = 0, b=0;
for ( int i=0; i<n; i++ ) {
sum += (x[i]*y[i+1]-x[i+1]*y[i]);
b += __gcd( abs(x[i]-x[i+1]), abs(y[i]-y[i+1]) );
}
if ( sum<0 ) sum=-sum;
cout << (sum-b+2)/2 << endl;
return 0;
}