BZOJ 3707: 圈地

3707: 圈地

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 236  Solved: 89
[Submit][Status][Discuss]

Description

2维平面上有n个木桩,黄学长有一次圈地的机会并得到圈到的土地,为了体现他的高风亮节,他要使他圈到的土地面积尽量小。圈地需要圈一个至少3个点的多边形,多边形的顶点就是一个木桩,圈得的土地就是这个多边形内部的土地。(因为黄学长非常的神,所以他允许圈出的第n点共线,那样面积算0)

Input

第一行一个整数n,表示木桩个数。
接下来n行,每行2个整数表示一个木桩的坐标,坐标两两不同。

Output

仅一行,表示最小圈得的土地面积,保留2位小数。

Sample Input

3
0 0
0 1
1 0

Sample Output

0.50

HINT

 

对于100%的数据,n<=1000。

 

Source

 
[Submit][Status][Discuss]

 

很喵的一道题,据说写个$O(N^{3})$的大暴力就能水过去,黄学长也介绍了一个随机化算法,但出题人还是想了个比较可以接受的正解的。

 

简单的说就是给定平面上n个点,求这n个点组成三角形的最小面积。

如果分别枚举三个点的话是$O(n^{3})$的,时间无法承受。

如果枚举了两个点a,b。设它们间的距离是L。如果以点a,b所在直线为y轴的话,与其他点所组成的三角形的面积$S=L*|x|/2$,x是其他点在这个坐标系中的横坐标。可以看出面积最小的就是离这个坐标系y轴最近的一个点。如果我们能够快速的得知最近的点的话,就可以将复杂度降低到$O(n^{2})$。

把这些点两两之间求出一条直线,记录这条直线是哪两个点取到的,记录这条直线的斜率k。然后按照k排序,我们可以依次按照k递增连续变化的顺序处理这些直线。

首先将这些点按x坐标排序,相当于按x=0直线排序的情况,考虑由两个相邻的斜率k1变到k2时,这个序列的改变只有k1直线的两个点的顺序交换了下,其它点之间的顺序都没变。在枚举直线时,交换两点维护序列即可。

—— ZRT学长

 

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int mxn = 1005;
 6 
 7 int n, m, p;
 8 
 9 double ans = 1e200;
10 
11 struct Pair
12 {
13     double x, y;
14     
15     inline Pair(void) {};
16     inline Pair(double a, double b)
17         : x(a), y(b) {};
18 }P[mxn];
19 
20 inline Pair operator - (const Pair &a, const Pair &b)
21 {
22     return Pair(a.x - b.x, a.y - b.y);
23 }
24 
25 struct Line
26 {
27     int a, b;
28     double k;
29     
30     inline void set(int i, int j)
31     {
32         a = i;
33         b = j;
34         
35         k = (P[i].y - P[j].y) / (P[i].x - P[j].x);
36     }
37 }L[mxn * mxn];
38 
39 inline bool cmpP(const Pair &a, const Pair &b)
40 {
41     if (a.x != b.x)
42         return a.x < b.x;
43     else
44         return a.y < b.y;
45 }
46 
47 inline bool cmpL(const Line &a, const Line &b)
48 {
49     return a.k < b.k;
50 }
51 
52 inline double cross(const Pair &a, const Pair &b)
53 {
54     return a.x * b.y - a.y * b.x;
55 }
56 
57 int ps[mxn], rk[mxn];
58 
59 signed main(void)
60 {
61     cin >> n;
62     
63     for (int i = 0; i < n; ++i)
64         cin >> P[i].x >> P[i].y;
65         
66     sort(P, P + n, cmpP);
67     
68     for (int i = 0; i < n; ++i)
69         for (int j = 0; j < i; ++j)
70             L[m++].set(i, j);
71     
72     sort(L, L + m, cmpL);
73     
74     for (int i = 0; i < n; ++i)
75         rk[i] = ps[i] = i;
76     
77     for (int i = 0; i < m; ++i)
78     {
79         int a = L[i].a, b = L[i].b;
80         
81         if (ps[a] > ps[b])swap(a, b);
82         
83         if (ps[a] > 1 - 1)ans = min(ans, fabs(cross(P[a] - P[b], P[rk[ps[a] - 1]] - P[b])));
84         if (ps[b] < n - 1)ans = min(ans, fabs(cross(P[a] - P[b], P[rk[ps[b] + 1]] - P[a])));
85         
86         swap(ps[a], ps[b]), swap(rk[ps[a]], rk[ps[b]]);
87     }
88     
89     cout << fixed << setprecision(2) << ans / 2.0 << endl;
90 }

 

@Author: YouSiki

 

posted @ 2017-02-15 14:08  YouSiki  阅读(422)  评论(0编辑  收藏  举报