皮克定理:
皮克定理用于计算点阵中顶点在格点上的多边形面积。对于一个顶点全部在格点上的多边形来说,它的面积计算有如下特点:
如果用a表示位于多边形内部的格点数,b表示位于多边形边界上的格点数,则多边形面积可表示为S = a + b/2 – 1 .
皮克定理演推:
假设平面是一张无穷大的网格,在每个格点处都有一个单位的热量,这些热量从各格点出发向周围辐射,最终把热量均匀地覆盖在整个平面上。现在,在平面上有一个格点多边形,我们把计算这个多边形的面积转化为计算多边形内部的热量总值。
先假设格点多边形只有顶点处是格点,边不经过格点,即格点n多边形边界上只有n个格点,此时我们考虑:假设每个格点对整个平面的热量贡献值相同,即每个格点在任一角度辐射出相同的能量使得平面被热量完全覆盖。我们选取无限接近于0的距离半径r,可以发现,所有位于多边形内部的格点都向多边形内部散发了360°的能量,而在多边形的顶点上,每个格点都向多边形内部散发了顶角处的角度能量,设顶角角度为m,则在此点处,顶角所贡献的能力是m / 360 ,而所有顶角角度加起来即为多边形的内角和。[n边形内角和计算公式:( n - 2 ) * 180] 即对于边界上有n个格点的n多边形来说,设a为多边形内部的格点数,b为多边形边界上的格点数,则多边形面积可以表示为:S = ( b - 2 ) * 180 / 360 + a * 360 / 360 =a + b / 2 – 1.
在上面演推的基础上,延伸至n多边形边界上有多于n个格点,即多边形的边经过格点。对于多边形的各个边,假若它们经过某些格点,那么这些格点一定向多边形内部辐射了180°的能量,即每增加一个边上的格点,结果都增加1 /2.即对于上式来说,每增加一个b,结果就增加b / 2.符合最后的公式,所以式子成立。从另一方面来讲,任何一个边经过格点的多边形,都可以分解成多个只有n个边界格点的n多边形,分别计算结果再拼接,仍然可得上述公式。
则最后可得结论,格点多边形面积可用公式S = a + b/2 – 1.表示,其中a表示位于多边形内部的格点数,b表示位于多边形边界上的格点数。
皮克定理的应用:
HDU 1705Count the grid
AC代码:
#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
struct point
{
int x,y;
} p[3],m[3];
int gcd(int a,int b)
{
int c;
while(b)
{
c=a%b;
a=b;
b=c;
}
return a;
}
int S(point p1,point p2,point p0)
{
return abs((p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x));
}
int main()
{
int sum,s,ans;
while(cin>>p[0].x>>p[0].y>>p[1].x>>p[1].y>>p[2].x>>p[2].y)
{
if(!p[0].x && !p[0].y && !p[1].x && !p[1].y && !p[2].x && !p[2].y)
break;
m[0].x=abs(p[0].x-p[1].x);
m[0].y=abs(p[0].y-p[1].y);
m[1].x=abs(p[1].x-p[2].x);
m[1].y=abs(p[1].y-p[2].y);
m[2].x=abs(p[0].x-p[2].x);
m[2].y=abs(p[0].y-p[2].y);
sum=gcd(m[0].x,m[0].y)+gcd(m[1].x,m[1].y)+gcd(m[2].x,m[2].y);
s=S(p[1],p[2],p[0]);
ans=(s-sum+2)/2;
cout<<ans<<endl;
}
}