凸包面积–分治法

凸包面积

Time Limit:   1000MS       Memory Limit:   65535KB
Submissions:   381       Accepted:   112
Description

麦兜是个淘气的孩子。一天,他在玩钢笔的时候把墨水洒在了白色的墙上。再过一会,麦兜妈就要回来了,麦兜为了不让妈妈知道这件事情,就想用一个白色的凸多边形把墙上的墨点盖住。你能告诉麦兜最小需要面积多大的凸多边形才能把这些墨点盖住吗? 现在,给出了这些墨点的坐标,请帮助麦兜计算出覆盖这些墨点的最小凸多边形的面积。

Input

多组测试数据。第一行是一个整数T,表明一共有T组测试数据。 每组测试数据的第一行是一个正整数N(0< N < = 105),表明了墨点的数量。接下来的N行每行包含了两个整数Xi和Yi(0<=Xi,Yi<=2000),表示每个墨点的坐标。每行的坐标间可能包含多个空格。

Output

每行输出一组测试数据的结果,只需输出最小凸多边形的面积。面积是个实数,小数点后面保留一位即可,不需要多余的空格。

Sample Input

240 01 00 11 120 00 1

Sample Output

1.00.0
这个算法可以这样表示:1.  将各点排序(必须的) ,为保证形成圈,把 P0 在次放在点表的尾部;2.  准备堆栈:建立堆栈 S,栈指针设为t,将0、1、2 三个点压入堆栈 S;3.  对于下一个点 i    只要 S[t-1]、S[t]、i不做左转      就反复退栈;    将 i压入堆栈 S4.堆栈中的点即为所求凸包;   其核心用 C 语言表示,仅仅是下面一段:     t=-1;      s[++t]=0; s[++t]=1; s[++t]=2;      for (i=3;i<n;i++)     {          while (!left(s[t-1],s[t],i))             t--;          s[++t]=i;     }下面我们来看一个例子:这是排序后的几个点

凸包面积--分治法


准备堆栈(有线段相连的点表示在栈中的点)
栈内元素:P0,P1,P2

凸包面积--分治法


考虑 P3:P1,P2,P3呈左转,P3入栈
栈内元素:P0,P1,P2,P3

凸包面积--分治法


考虑 P4:P2,P3,P4呈左转,P4入栈
栈内元素:P0,P1,P2,P3,P4

凸包面积--分治法


考虑 P5:P3,P4,P5非左转,退栈
栈内元素:P0,P1,P2,P38

凸包面积--分治法


现在,P2,P3,P5 呈左转,P5入栈
栈内元素:P0,P1,P2,P3,P5
(此时情况如图,算法舍弃了 P4)

凸包面积--分治法


以此方法进行下去,直到所有点都被考虑过
最终的栈中元素为 P0,P1,P2,P3,P8,P0,正是所求凸包
擦去其他点后,如图所示:

凸包面积--分治法


   如果给定点集有 n个点,则此过程的算法复杂度为 O(n),加上排序的过程,
整个算法复杂度是 O(nlogn)
C++代码
  1 #include <iostream>
2 #include <algorithm>
3 #include <stack>
4 #include <iomanip>
5 #define max 106
6 using namespace std;
7
8 struct point
9 {
10 int x, y;
11 };
12
13 point spot[max], p0;
14 //p1p2距离
15 int dis(const point &p1, const point &p2)
16 {
17 return (p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y);
18 }
19 //p1在p1p2左侧
20 bool compares(const point &p1, const point &p2)
21 {
22 int t;
23 t = (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
24 if(t > 0 || (t == 0 && dis(p1, p0) < dis(p2, p0)))
25 return true;
26 else
27 return false;
28 }
29 double area(point p1,point p2,point p3) //计算三角形面积;
30 {
31 double s;
32 s=(p1.x*(p2.y-p3.y)+p2.x*(p3.y-p1.y)+p3.x*(p1.y-p2.y))/2.0;
33 return s;
34 }
35 int main()
36 {
37 int n, i, x, y, p,m;
38 stack<point> s;
39 cin>>m;
40 while(m--)
41 {
42 cin>>n;
43 for(i = 0; i < n; i++)
44 cin>>spot[i].x>>spot[i].y;
45 x = spot[0].x;
46 y = spot[0].y;
47 p = 0;
48 for(i = 1; i < n; i++) //寻找最左上的点
49 {
50 if((spot[i].y == y && spot[i].x < x)||spot[i].y < y)
51 {
52 x = spot[i].x;
53 y = spot[i].y;
54 p = i;
55 }
56 }
57 //x,y为最做点,即p0确定
58 p0.x = x;
59 p0.y = y;
60
61 swap(spot[0], spot[p]);
62 sort(spot + 1, spot + n, compares);
63 //将0、1、2 三个点压入堆栈 S
64 s.push(p0);
65 s.push(spot[1]);
66 s.push(spot[2]);
67
68 point temp;
69 for(i = 3; i < n; i++) //凸包
70 {
71 while(!s.empty())
72 {
73 temp = s.top();
74 s.pop();
75 p = (s.top().x)*temp.y+spot[i].x*(s.top().y)+temp.x*(spot[i].y)-spot[i].x*(temp.y)-temp.x*(s.top().y)-s.top().x*(spot[i].y);
76 if(p>0)//i位于spot[t-1]spot[t]左侧
77 {
78 s.push(temp); //将temp重新压入栈中
79 break;
80 }
81 }
82 s.push(spot[i]); //将i 压入栈中
83 }
84
85 double area = 0;
86 temp = s.top();
87 s.pop();
88 area += (p0.x * temp.y - p0.y * temp.x)/2.0;
89 while(!s.empty())
90 {
91 area += (temp.x * s.top().y - temp.y * s.top().x)/2.0;
92 temp = s.top();
93 s.pop();
94 }
95 if (n<=2)
96 {
97 area =0;
98 }
99 if(area < 0)
100 {
101 area = -area;
102 }
103 cout<<setiosflags(ios::fixed)<<setprecision(1)<<area<<endl;
104 }
105
106 return 0;
107 }

原文链接: https://www.cnblogs.com/qingfeideyi/archive/2011/10/12/2209417.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    凸包面积--分治法

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/34147

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月8日 上午11:09
下一篇 2023年2月8日 上午11:11

相关推荐