计算几何 --- 凸包 模板

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;
}

  

posted @   北岛知寒  阅读(244)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示
主题色彩