和吴昊一起玩推理 Round 8 —— 计算几何一系列(B)(HDOJ 1705)
(Source:HDOJ 1705)如下,就是一个Grid(方格),有一个封闭的多边形(多边形是规则的),有些点在多边形内,有些在边的表面上,而有些则在多边形的外侧。利用那一个个正方形网格,可以计算出多边形所围住的区域的总面积。
何谓皮克定理?
如果取一个格点做原点O,取通过这个格点的横向和纵向两直线分别做横坐标轴OX和纵坐标轴OY,并取原来方格边长做单位长,建立一个坐标系。这时前面所说的格点,显然就是纵横两坐标都是整数的那些点。如图1中的O、P、Q、M、N都是格点。由于这个缘故,我们又叫格点为整点。
一个多边形的顶点如果全是格点,这多边形就叫做格点多边形。有趣的是,这种格点多边形的面积计算起来很方便,只要数一下图形边线上的点的数目及图内的点的数目,就可用公式算出。
这个公式是皮克(Pick)在1899年给出的,被称为“皮克定理”,这是一个实用而有趣的定理。
给定顶点坐标均是整点(或正方形格点)的简单多边形(条件),皮克定理说明了其面积S和内部格点数目a、边上格点数目b的关系:
S=a+ b/2 - 1(其中a表示多边形内部的点数,b表示多边形边界上的点数,S表示多边形的面积)
如何证明皮克定理?
可以将边界上的点看作是一个个圆,在多边形边上的圆其面积只有一半属于这个多边形,但多边形角上的圆就不一样了,将夹角的任一个边延长,与另一条边的夹角是外角,这角上的圆中外角部分计算面积时多算了,要除去,因多边形的外角和是360度,所以正好是个整圆(吴昊评注:所以说三角形的外角和按照“师法自然”的规则来说,应该是360度,这样也可以突出其普遍性,因为,多边形的各个内角和有不同,而外角和却都是360度,所以可见一斑)。
所以面积公式为a+1/2*b-1
皮克公式是奥地利数学家皮克发现了一个计算点阵中多边形面积公式:S=a+1/2*b-1其中a表示多边形内部的点数,b表示多边形边界上的点数,S表示多边形的面积,可以自己带入一下。
如果a=3,b=10,所以多边形面积S=3+1/2X10-1=7
以下的这个Program,输入三角形的三个点的(x,y)坐标,可以得到三角形内的总点数。
2 #include<math.h>
3 using namespace std;
4
5 //定义一个点
6 struct point
7 {
8 int x,y;
9 }p[3];
10
11 //定义每相邻两个点之间的差值(abs绝对值),因为,三角形各个点之间都是相邻的嘛
12 struct node
13 {
14 int fx,fy;
15 }m[3];
16
17 //GCD,最大公约数,另外一个含义,你懂的
18 int gcd(int a,int b)
19 {
20 //开始的时候判断一下,可以省去一些差值等于0的情况,节约一步
21 if(b==0) return a;
22 return gcd(b,a%b);
23 }
24
25 //绝对值,这个用标准库中的标准函数也是可以的
26 int ABS(int x)
27 {
28 return x>0?x:-x;
29 }
30
31 //这个是求三角形面积的一个固定方法,采用这种思路,可以扩展到多边形面积的计算,其本质依然是点乘
32 int AREA(point p1,point p2,point p0)
33 {
34 return ABS((p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x));
35 }
36
37 int main()
38 {
39 int sum,area,ans;
40 while(scanf("%d%d%d%d%d%d",&p[0].x,&p[0].y,&p[1].x,&p[1].y,&p[2].x,&p[2].y)!=EOF)
41 {
42 if(p[0].x==0&&p[0].y==0&&p[1].x==0&&p[1].y==0&&p[2].x==0&&p[2].y==0) break;
43 m[0].fx=ABS(p[0].x-p[1].x);
44 m[0].fy=ABS(p[0].y-p[1].y);
45 m[1].fx=ABS(p[1].x-p[2].x);
46 m[1].fy=ABS(p[1].y-p[2].y);
47 m[2].fx=ABS(p[0].x-p[2].x);
48 m[2].fy=ABS(p[0].y-p[2].y);
49 //这里利用最大公约数的方法可以得到有多少点在边上,也就是a的值
50 sum=gcd(m[0].fx,m[0].fy)+gcd(m[1].fx,m[1].fy)+gcd(m[2].fx,m[2].fy);
51 //求面积S
52 area=AREA(p[1],p[2],p[0]);
53 //利用a和S,求b,这里遵循的是皮克公式
54 ans=(area-sum+2)/2;
55 printf("%d\n",ans);
56 }
57 return 0;
58 }