POJ1113:Wall (凸包算法学习)
题意:
给你一个由n个点构成的多边形城堡(看成二维),按顺序给你n个点,相邻两个点相连。
让你围着这个多边形城堡建一个围墙,城堡任意一点到围墙的距离要求大于等于L,让你求这个围墙的最小周长(看成二维平面)(结果四舍五入
分析:
凸包问题和这个问题的差别就在于:凸包问题没有“城堡任意一点到围墙的距离要求大于等于L”这个要求
凸包:找到一个凸多边形把这n个点形成的多边形围起来,找到的那个周长最小的凸多边形就是我们所求的凸包
那么这个问题怎么在凸包的基础上解决呢?
我们考虑L,对于求出的凸多边形,对于它的顶点X,可以证明每个X附近需要增加一定的圆弧来保证顶点到圆弧的距离大于等于L,
所有X的圆弧角度之和为Pi,将凸包平移与圆弧连接成封闭图案,最终 ans=凸包+2*Pi*L。如下图(参考:https://my.oschina.net/u/4331110/blog/4250115)
上图中黑色实线连起来的多边形就是题目给出的n个点形成的多边形
我们就是要在这个基础上满足题目“城堡任意一点到围墙的距离要求大于等于L”要求
如上图所示,也就只需要多加4段圆弧就可以满足题目需求,答案也就是ans=凸包+2*Pi*L
凸包怎么求(参考:https://www.cnblogs.com/czaoth/p/6912073.html)?
这里我们使用Graham Scan算法来实现,此算法能够在O(nlogn)的时间内找到凸包。
这里说一下二维平面下叉积的几何意义:对于二维向量a=(x1,y2)和b=(x2,y2),a×b定义为x1*y2-y1*x2。而它的几何意义就是|a||b|sin<a,b>。如果a与b夹角小于180度(逆时针),那么这个值就是正值,大于180度就是负值。需要注意的是,左乘和右乘是不同的。这里给出几个例子
我认为这个sin<a,b>就是:a向量按照逆时针移动到b向量同方向的角度
Graham Scan算法过程:
Graham Scan算法的做法是先定下一个起点,一般是最左边的点和最右边的点(需要排序后选择起点),然后一个个点扫过去,如果新加入的点和之前已经找到的点所构成的“壳”凸性没有变化,就继续扫,否则就把已经找到的最后一个点删去,再比较凸性,直到凸性不发生变化。分别扫描上下两个“壳”,合并在一起,凸包就找到了。
我们找下“壳”,上下其实是一样的。首先加入两个点A和C:
然后插入第三个点G,并计算AC×CG的叉积,却发现叉积小于0,也就是说逆时针方向上∠ACG大于180度,于是删去C点,加入G点:
然后就是依照这个步骤便能加入D点。在AD上方是以D为起点。就能够找到AGD和DFEA两个凸壳。合并就得到了凸包。
关于扫描的顺序,有坐标序和极角序两种。坐标序是比较两个点的x坐标,如果小的先被扫描(扫描上凸壳的时候反过来);如果两个点x坐标相同,那么就比较y坐标,小的先被扫描(扫描上凸壳的时候也是反过来)。极角序使用arctan2函数的返回值进行比较
给出POJ1113:Wall代码:
1 #include<stdio.h>
2 #include<string.h>
3 #include<iostream>
4 #include<algorithm>
5 #include<queue>
6 #include<stack>
7 #include<map>
8 #include<math.h>
9 using namespace std;
10 const int maxn=1e3+10;
11 const double PI=acos(-1.0); //180度的弧度制
12 const double eps=1e-6;
13 struct Cpoint
14 {
15 double x,y;
16 Cpoint(){}
17 Cpoint(double xx,double yy):x(xx),y(yy){}
18 Cpoint friend operator -(Cpoint a,Cpoint b)
19 {
20 return Cpoint(a.x-b.x,a.y-b.y);
21 }
22 double friend operator ^(Cpoint a,Cpoint b)
23 {
24 return a.x*b.y-b.x*a.y;
25 }
26 bool friend operator <(Cpoint a,Cpoint b)
27 {
28 if(a.y==b.y) return a.x<b.x;
29 return a.y<b.y;
30 }
31 }point[maxn];
32 double dist(Cpoint a,Cpoint b)
33 {
34 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
35 }
36 int Sign(double x)
37 {
38 if(x>=-eps && x<=eps) return 0;
39 if(x>eps) return 1;
40 else return -1;
41 }
42 bool cmp(Cpoint a,Cpoint b)
43 {
44 int s=Sign((a-point[1])^(b-point[1]));
45 if(s>0 || (s==0 && dist(a,point[1])<dist(b,point[1]))) return 1;
46 else return 0;
47 }
48 int n,l;
49 double Graham()
50 {
51 double res=0;
52 sort(point+1,point+1+n); //得到原点(原点一般让两端的点来当)
53 sort(point+1,point+1+n,cmp); //得到积角序
54 int que[maxn],top=3;
55 que[1]=1;
56 que[2]=2;
57 que[3]=3;
58 for(int i=4;i<=n;++i)
59 { //注意下面点的顺序不要写错了
60 while(top>1 && Sign((point[que[top]]-point[que[top-1]])^(point[i]-point[que[top]]))<=0)
61 top--;
62 que[++top]=i;
63
64 }
65 for(int i=1;i<top;++i)
66 {
67 res+=dist(point[que[i]],point[que[i+1]]);
68 //printf("%.2lf**\n",res);
69 }
70 res+=dist(point[que[1]],point[que[top]]);
71 res+=2.0*PI*l;
72 return res;
73 }
74 int main()
75 {
76 while(~scanf("%d%d",&n,&l))
77 {
78 for(int i=1;i<=n;++i)
79 scanf("%lf%lf",&point[i].x,&point[i].y);
80 printf("%d\n",(int)(Graham()+0.5));
81 }
82 return 0;
83 }
POJ1113:Wall (凸包算法学习)的更多相关文章
- POJ1113 Wall —— 凸包
题目链接:https://vjudge.net/problem/POJ-1113 Wall Time Limit: 1000MS Memory Limit: 10000K Total Submis ...
- POJ1113:Wall (凸包:求最小的多边形,到所有点的距离大于大于L)
Once upon a time there was a greedy King who ordered his chief Architect to build a wall around the ...
- POJ1113 Wall 凸包
题目大意:建立围墙将城堡围起来,要求围墙至少距离城堡L,拐角处用圆弧取代,求围墙的长度. 题目思路:围墙长度=凸包周长+(2*PI*L),另外不知道为什么C++poj会RE,G++就没问题. #inc ...
- Graham Scan凸包算法
获得凸包的算法可以算是计算几何中最基础的算法之一了.寻找凸包的算法有很多种,Graham Scan算法是一种十分简单高效的二维凸包算法,能够在O(nlogn)的时间内找到凸包. 首先介绍一下二维向量的 ...
- POJ1113 Wall
题目来源:http://poj.org/problem?id=1113题目大意: 如图所示,给定N个顶点构成的一个多边形和一个距离值L.建立一个围墙,把这个多边形完全包含在内,且围墙距离多边形任一点的 ...
- DSP算法学习-过采样技术
DSP算法学习-过采样技术 彭会锋 2015-04-27 23:23:47 参考论文: 1 http://wr.lib.tsinghua.edu.cn/sites/default/files/1207 ...
- 算法学习之C语言基础
算法学习,先熟悉一下C语言哈!!! #include <conio.h> #include<stdio.h> int main(){ printf(+); getch(); ; ...
- Python之路,Day21 - 常用算法学习
Python之路,Day21 - 常用算法学习 本节内容 算法定义 时间复杂度 空间复杂度 常用算法实例 1.算法定义 算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的 ...
- C / C++算法学习笔记(8)-SHELL排序
原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...
随机推荐
- 细说 js 的7种继承方式
在这之前,先搞清楚下面这个问题: function Father(){} Father.prototype.name = 'father'; Father.prototype.children = [ ...
- 阿里云OSS整合
一.对象存储OSS 为了解决海量数据存储与弹性扩容(主要是静态文件的存储例如图片,语音,视频等),项目中我们通常采用云存储的解决方案- 阿里云OSS. 1.开通"对象存储OSS"服 ...
- Zabbix 4.0.24 完整安装
依赖包安装: yum install net-snmp* libssh-devel libssh2-devel -y Zabbix server安装: wget https://cdn.zabbix. ...
- 翻译 - ASP.NET Core 托管和部署 - 在 Linux 上使用 Nginx 托管 ASP.NET Core 网站
翻译自 https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-5.0 本文介 ...
- 【ORA】ORA-00030: User session ID does not exist.
今天巡检,查询锁相关的情况的时候,确认业务后,准备将锁干掉,但是干掉的时候报了一个错误,ORA-00030 发现回话不存在,我以为pmon进程已经将锁进程kill掉了,就再次查看,发现,还是存在 这个 ...
- 微软官网下载win10离线介质
1.打开google浏览器 2.搜索win10官网下载或者直接输入网址https://www.microsoft.com/zh-cn/software-download/windows10 3.按F1 ...
- 敏捷史话(四):敏捷是人的天性 —— Arie van Bennekum
敏捷是人的天性,是你与生俱来的东西.面对敏捷,Arie van Bennekum 下了这样一个结论. 但这并不意味着人们只能通过天赋获得敏捷,对于想要学习敏捷的人来说,敏捷绝不是仅仅靠学习僵化的框架. ...
- Windows安全加固
Windows安全加固 # 账户管理和认证授权 # 1.1 账户 # 默认账户安全 # 禁用Guest账户. 禁用或删除其他无用账户(建议先禁用账户三个月,待确认没有问题后删除.) 操作步骤 本地用户 ...
- px转rem的填坑之路
这是要为一个vue项目做自适应,设计稿是1920*1080的,要适应各种手机.ipad.3840*2160的超大屏,所以就选择了rem,包用的是 postcss-pxtorem 在适配的时候遇到了很多 ...
- SDNU_ACM_ICPC_2021_Winter_Practice_1st [个人赛] 2021.1.19 星期二
SDNU_ACM_ICPC_2021_Winter_Practice_1st [个人赛] K - Color the ball 题意: 有n个气球,每次都给定两个整数a,b,给a到b内所有的气球涂一个 ...