学习记录
兴起捡起很久以前就研究过的凸包。
还是没有在学校共享里找到资料……
没有办法,只能又推荐dalao的博客了……
配合板题食用更佳!
P2742 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows
进入正题
凸包可广泛运用于各种求最小点覆盖问题,方法千奇百怪,这里只列举三种。
涉及到向量的应用。
给出 个点的坐标,求最短的能够围住这些点的多边形的周长。
引用一张经典的图:
法一:暴力枚举法
暴力出奇迹,水法真神奇
基本思想
枚举两点,判断其余点是否在这两点所在直线的一侧:
若是,则这两点为凸包上的点;
若不是,则继续枚举。
法二:Graham扫描法
基本思想
- 以 坐标最小的点为原点,建系
- 将点按照极角大小排序
- 将当前点与栈顶边比较:若当前点在栈顶边的右侧,弹出栈顶点,重复当前步骤,否则进行下一步
- 若当前点在栈顶边的左侧,将当前点加入栈,更换当前点
时间复杂度:
法三:Melkman算法
Melkman算法是当前世界上公认的最优秀求凸包算法。
已知上述两种算法都是离线算法,而Melkman算法是在线算法。
时间复杂度:
(显然优于目前其他任何算法)
经过反复斟酌,这位dalao的博客是比较详细且优秀的,这里不再赘述。
(你就是想掩饰你不会)
具体用途与实现
P2742 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows
Code
//不知道CSDN的Markdown是不是萎了,颜色渲染有点问题,凑合着看吧,也不知道什么时候修。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
struct Dot
{
double x, y;
int pos;
Dot(double _x = 0, double _y = 0)
{
x = _x, y = _y;
}
};
struct Line
{
Dot p, v;
Line() {}
Line(Dot _p, Dot _v)
{
p = _p, v = _v;
}
};
Dot operator+(Dot a, Dot b) {return Dot(a.x + b.x, a.y + b.y);}
Dot operator-(Dot a, Dot b) {return Dot(a.x - b.x, a.y - b.y);}
Dot operator*(Dot a, double b) {return Dot(a.x * b, a.y * b);}
double DotTimes(Dot a, Dot b) {return a.x * b.x + a.y * b.y;}
double CrossTimes(Dot a, Dot b) {return a.x * b.y - a.y * b.x;}
double Len(Dot a) {return sqrt(DotTimes(a, a));}
double Dist(Dot a, Dot b) {return Len(a - b);}
bool Direct(Dot a, Dot b) {return CrossTimes(a, b) < 0;}
const int MAXN = 10000;
const int Maxint = 2147483647;
int n;
Dot src = Dot(0, Maxint);
Dot d[MAXN + 1];
int q[MAXN + 1];
double ans;
bool cmp(Dot a, Dot b)
{
double tmp = CrossTimes(a, b);
if (tmp == 0)
return Len(a) < Len(b);
else
return tmp > 0;
}
int main(int argc, char const *argv[])
{
//freopen("init.in", "r", stdin);
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%lf%lf", &d[i].x, &d[i].y);
d[i].pos = i;
if (d[i].y < src.y)
src = d[i];
}
for (int i = 1; i <= n; i++)
{
int tmp = d[i].pos;
d[i] = d[i] - src;
d[i].pos = tmp;
}
sort(d + 1, d + n + 1, cmp);
for (int i = 1; i <= n; i++)
{
while ((Direct(d[q[q[0]]] - d[q[q[0] - 1]], d[i] - d[q[q[0]]])) && (q[0] > 2))
q[0]--;
q[++q[0]] = i;
}
q[q[0] + 1] = q[1];
for (int i = 1; i <= q[0]; i++)
ans += Len(d[q[i + 1]] - d[q[i]]);
printf("%.2lf\n", ans);
return 0;
}