计算几何 --- 凸包 模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | //Memory Time // 1347K 0MS // by : Snarl_jsb #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<vector> #include<queue> #include<stack> #include<map> #include<string> #include<climits> #include<cmath> #define MAX 1100 #define N 1000 #define INF 1000000 #define LL long long using namespace std; struct point { int x,y; //横纵坐标 : x,y double len,theta; //与参考点的距离 len 与参考点构成的向量与 (1,0)向量构成的夹角的余弦值 theta }g[N]; //定义了一个全局变量,记录凸包中的点 /*--------按余弦值,从大到小快速排序--------*/ void qsort ( int st, int en) { int i=st,j=en; g[0]=g[i]; while (i<j) { while (i<j && g[0].theta>=g[j].theta) j--; if (i<j) { g[i]=g[j]; i++; } while (i<j && g[0].theta<=g[i].theta) i++; if (i<j) { g[j]=g[i]; j--; } } g[i]=g[0]; if (st<i-1) qsort (st,i-1); if (i+1<en) qsort (i+1,en); } /*-----------Graham 扫描法-------------*/ void graham( int *n) { /*第一步,寻找y坐标最小,然后x坐标最小的点*/ int p=1; for ( int i=2;i<=*n;i++) if ((g[i].y<g[p].y)||(g[i].y==g[p].y && g[i].x<g[p].x)) p=i; g[0]=g[p]; g[p]=g[1]; g[1]=g[0]; /*找到该点,并把它存放在 g 中的第一个元素的位子上*/ /*第二步,计算所有的点距离参考点的距离(len) 还有夹角的余弦值 (theta)*/ for ( int i=2;i<=*n;i++) { g[i].len= sqrt ((g[i].x-g[1].x)*(g[i].x-g[1].x)+(g[i].y-g[1].y)*(g[i].y-g[1].y)); g[i].theta=100*(g[i].x-g[1].x)/g[i].len; } qsort (2,*n); //先根据夹角的余弦值从大到小排序 /*第三步,将所有theta值相等的点,只保存len值最大的,存放在数组map中*/ point map[N]; int tot=0; p=1; while (p<=*n) { int k=p; while ( fabs (g[p].theta-g[p+1].theta)<=1e-6) { if (g[p+1].len>g[k].len) k=p+1; p++; } map[++tot]=g[k]; p++; } /*第四步,对map中的元素扫描一遍,确定凸包的元素,放在数组g中*/ *n=tot; tot=3; //先做了一个小小的处理,使得自己更好理解 memset (g,0, sizeof (g)); g[1]=map[1]; g[2]=map[2]; g[3]=map[3]; //先将前三个点入栈 g for ( int i=4;i<=*n;i++) //依次用map中的每个点对g中的点进行一次判断,看是否是属于凸包 { double chaji=(g[tot].x-g[tot-1].x)*(map[i].y-g[tot].y)-(map[i].x-g[tot].x)*(g[tot].y-g[tot-1].y); for (;chaji<=0 && tot>=1;) //如果旋转的方向不同,g[tot]这个点就不是,删除,并继续判断 g 中下一个点是不是 { tot--; chaji=(g[tot].x-g[tot-1].x)*(map[i].y-g[tot].y)-(map[i].x-g[tot].x)*(g[tot].y-g[tot-1].y); } g[++tot]=map[i]; //将map[i]这个点入栈,至于是否是属于凸包中的点,等待以后的点来判断 } *n=tot; //凸包处理完,总共有tot个凸包上的点 } int main() { //freopen("C:/Users/chengfeng/Desktop/in.txt","r",stdin); int n; while ( scanf ( "%d" ,&n)!=EOF) { for ( int i=1;i<=n;i++) scanf ( "%d%d" ,&g[i].x,&g[i].y); graham(&n); for ( int i=1;i<=n;i++) printf ( "(%d,%2d)\n" ,g[i].x,g[i].y); } return 0; } |
作者:北岛知寒
出处:https://www.cnblogs.com/crazyacking/p/3915511.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?