写到usaco上的一题可能题解是凸包所以转来这篇文章看看
来源:互联网 发布:公交数据库下载 编辑:程序博客网 时间:2024/05/19 18:40
凸包 graham 算法
版权声明:本文为博主原创文章,未经博主允许不得转载。
向量:
1.向量的内积(数量积,点乘):
公式:a· b = |a| * |b| cos<a, b>=a.x* b.y + b.x * a.y
2.向量的外积(向量积,差乘):
公式:|c|= |a|*|b|*sin<a, b> = a.x * b.y - b.x * a.y
意义:
1).两个向量和坐标原点所围成的面积(可正可负)。
2).值为正值表示向量a在向量b的顺时针方向,反之,向量a在向量b的逆时针方向,相等时,共线.
凸包:由平面上的最小点所围成的多边形,平面上任何其它的点都在这个多边形内部,这个多边形就称为
凸包。
(图1)
graham算法:
第一步:选取x轴坐标最小的点,如果存在多个选y轴坐标最小的点.(如图1,p0点)
第二步:排序.从下到上扫描有其它点.(如图1)扫描的结果顺序,p0, p4, p5, p7, p9,p6, p8, p2,p3, p1.
数学公式向量的外积模公式:|c|(是模不是绝对值符号)= |a|*|b|*sin<a, b> = a.x * b.y – b.x * a.y
|c|> 0:向量a在向量b的顺时针方向,因为此例原点坐标取x轴坐标最小的点,所以,向量a在向
量b的下方.(p0-p4线段在p0-p5的下方).
|c|= 0:共线时,按照与原点距离由小到大的顺序.
第三步:按照第二步得到的顶点顺序进行graham扫描.按照本例选取的原点方式,当扫描到左拐(p0,p4, p5)时保留(p4),右拐(p9,p6, p8)时删除顶点(p6),结果就是凸包的顶点集.(绿线扫描的顺序,红线为左拐点).共线时,删除距离较小的点.
注意:右拐删除结点时,必须回溯与前面保留的点重新比较,因为删除一个点后先前拐点性质会发生变化
例如:删除p6后,(p7, p9, p8) 也是右拐了.
所谓的左拐/右拐就沿着边界扫描后,其它的点是否在当前点与下一点连线与原点的内部.
例如:结果p7-p8是凸包的顶点,p7-p8直线会把所有其它点挡在原点p0方向的一侧.
数学公式:
向量外积模公式
例:
p5– p4向量Xp0 – p4 向量>0, (p5–p4)在(p0–p4)的顺时针方向,左拐
p8– p6向量Xp9 – p6向量<0, (p8–p6)在(p9–p6)的逆时针方向,右拐
也可以采用其它向量方式
例:
p4–p0向量Xp5–p0向量>0, (p4–p0)在(p5–p0)的顺时针方向,左拐
p6–p9向量Xp8–p9向量<0, (p6–p9)在(p8–p9)的逆时针方向,右拐
示例程序:
p0:(1, -2)
p1:(1, 2)
p2:(5, 3)
p3:(4,5)
p4:(2, -4)
p5:(6, -6)
p6:(7, 0)
p7:(10, -3)
p8:(9, 4)
p9:(8, -1)
input:
10
1 -2
1 2
5 3
4 5
2 -4
6 -6
7 0
10-3
9 4
8 -1
output:
1 -2
2 -4
6 -6
10-3
9 4
4 5
1 2
源代码:
#include <iostream>
#include <algorithm>
#include <vector>
#include <fstream>
#define MAX_NUMS 10
typedef struct
{
int x;
int y;
} veritice;
veritice vet[MAX_NUMS];
int n;
std::vector<veritice> v;
inline int cross(const veritice& p0, const veritice& p1, const veritice& p2)
{
veritice u, v;
u.x = p1.x - p0.x, u.y = p1.y - p0.y;
v.x = p2.x - p0.x, v.y = p2.y - p0.y;
return v.x * u.y - u.x * v.y;
}
inline int distance(const veritice& p1, const veritice& p2)
{
return (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y);
}
inline int graham_compare(const void* a, const void* b)
{
int result = cross(vet[0], *(veritice*)a, *(veritice*)b);
if(result)
return result;
return distance(vet[0], *(veritice*)a) - distance(vet[0], *(veritice*)b);
}
inline void graham_scan()
{
v.push_back(vet[0]);
v.push_back(vet[1]);
for(int i = 2; i < n; i++)
{
while( cross(v[v.size() - 1], v[v.size() - 2], vet[i]) <= 0)
v.pop_back();
v.push_back(vet[i]);
}
}
int main()
{
std::ifstream in("case_in");
int index = 0;
in >> n;
for(int i = 0; i < n; i++)
{
in >> vet[i].x >> vet[i].y;
if(vet[0].x > vet[i].x || (vet[0].x == vet[i].x && vet[0].y > vet[i].y))
index = i;
}
in.close();
// 第一步
veritice temp;
temp.x = vet[0].x, temp.y = vet[0].y;
vet[0].x = vet[index].x, vet[0].y = vet[index].y;
vet[index].x = temp.x, vet[index].y = temp.y;
// 第二步
qsort(vet + 1, n - 1, sizeof(veritice), graham_compare);
// 第三步
graham_scan();
// 输出
for(unsigned int i = 0; i < v.size(); i++)
std::cout << v[i].x << ' ' << v[i].y << std::endl;
return 0;
}
- 写到usaco上的一题可能题解是凸包所以转来这篇文章看看
- 最近对#特别的迷恋,所以特别搞了这篇文章来谈谈#的掉率
- 浮躁的时候看看这篇文章
- 算法导论 9.1-1 求第二小元素 (这篇文章写的很好转来学习)
- <![CDATA[]]>和转义字符 (注:这篇文章是本人在其他地方看到的,刚好项目中mybatis用到了,所以转来分享)
- servelet portlet比较(由于公司只能上技术网站,所以将这篇文章转载到csdn,方便在公司看)
- 转来这篇文章给大伙儿分享分享,写的挺实在的,希望大家2011有更多的收获。
- 昨天想看看电子书,看到一人的博客写的好。就想弄了下来,存到手机自己看看。
- 当你浮躁的时候,看看这篇文章
- [转] 觉得累了,可以看看这篇文章
- 谢谢写这篇文章的人
- 【转】如果这两天股市的震荡还没让你清醒的话,应该看看这篇文章
- 今天在CSDN上看了这篇文章,写的深刻,收藏。
- 到CSDN 安家了!!!!!!!欢迎来我的小屋看看
- 指针(详解)本人觉得写的很不错,所以拿出来分享!
- 指针(详解)本人觉得写的很不错,所以拿出来分享
- [推荐] 指针(详解)本人觉得写的很不错,所以拿出来分享
- [推荐] 指针(详解)本人觉得写的很不错,所以拿出来分享
- 真机调试NSLog不打印日志信息
- OpenGL 编程与 FBO
- opencv之图像二值化处理threshold
- 40个Java多线程问题总结
- 零基础读懂视频播放器控制原理——ffplay播放器源代码分析(一)
- 写到usaco上的一题可能题解是凸包所以转来这篇文章看看
- privoxy安装
- H5项目常见问题及注意事项
- API
- Android源码编译GC overhead limit exceeded. Try increasing heap size with java option '-Xmx<size>'
- POJ3692【二分匹配】
- 【python3.5 tkinter】页面跳转
- 谷歌大脑全新软件能让马赛克样模糊人脸变清晰
- WebApi 4大方法get、post、put、delete返回协议