POJ 1113 Wall 计算几何 Graham's Scan 求凸包

凸包问题

首先将所有点按y左边递增排序。若遇到y坐标值相等,则x坐标最小的点优先。此时获得的第一个点(p[0])作为基点。

第二次排序。排序依据:基点到其他点构成的向量与x轴逆时针方向夹角大小。

求解凸包过程。首先将p[0]、p[1]两个点加入到路径中,用一个next保存路径的栈顶。每次和下一个点p[i]比较时,判断path[next]和p[i]各自到path[next - 1]构成的向量的夹角。如果是逆时针(大于0),将p[i]加入到路径栈。否则,next回退一步,即删除栈顶。如果这时的栈顶仍不满足条件,继续回退。直到条件成立(构成逆时针,且和p[i]构成的向量不共线),那么才将p[i]压栈。然后继续下个点的判断。

扫尾部分。凸包已经建立好,根据题意,只要求出两两点之间距离,和圆角总周长(其实就是一个圆周),全部相加四舍五入就是答案了。

 

 1 #include<iostream>
2 #include<cmath>
3 #include<algorithm>
4 using namespace std;
5
6 struct Point {
7 int x, y;
8 };
9 const double PI = acos(-1.0);
10 int n, close;
11 Point p[1001], path[1001];
12
13 bool cmpY(const Point p1, const Point p2)
14 {
15 if(p1.y == p2.y)
16 return p1.x < p2.x;
17 return p1.y < p2.y;
18 }
19
20 double dis(const Point p1, const Point p2)
21 {
22 return sqrt((double)(p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
23 }
24
25 int xmulti(const Point p1, const Point p2, const Point p0)
26 {
27 return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
28 }
29
30 bool cmpConvex(const Point p1, const Point p2)
31 {
32 int far = xmulti(p1, p2, p[0]);
33 if(far == 0)
34 {
35 return dis(p1, p[0]) < dis(p2, p[0]); //如果两个点构成的向量共线,则取距离最近的点
36 }
37 return far > 0;
38 }
39
40 int graham()
41 {
42 int next = 1; //表示当前进行到第几个点
43 sort(p, p + n, cmpY); //找出离原点最近的点
44 sort(p + 1, p + n, cmpConvex);
45 //将前两个点先加入路径中
46 path[0] = p[0];
47 path[1] = p[1];
48 for(int i = 2; i < n; i++)
49 {
50 if(xmulti(path[next], p[i], path[next - 1]) > 0)
51 {
52 path[++next] = p[i];
53 }
54 else
55 {
56 --next;
57 //如果仍然不满足构成的方向为逆时针,继续回退
58 //当然,构成的向量共线的点也一并删除,减少多余计算
59 while(next > 1 && xmulti(path[next], p[i], path[next - 1]) <= 0)
60 {
61 --next;
62 }
63 //删去不满足条件的点后,将当前点加入路径中
64 path[++next] = p[i];
65 }
66 }
67 path[++next] = p[0];
68
69 return next + 1; //因为++next写法原因,返回值需要+1
70 }
71
72 int main()
73 {
74 double sum = 0;
75 scanf("%d%d", &n, &close);
76 for(int i = 0; i < n; i++)
77 scanf("%d%d", &p[i].x, &p[i].y);
78 int next = graham();
79
80 for(int i = 1; i < next; i++)
81 sum += dis(path[i], path[i - 1]);
82 sum += 2 * PI * close;
83
84 printf("%d\n", (int)(sum + 0.5));
85
86 return 0;
87 }

 

posted @ 2012-02-23 20:51  dgsrz  阅读(303)  评论(0编辑  收藏  举报