凸包模板(分治 or Graham扫描法)
来源:互联网 发布:ubuntu 32 编辑:程序博客网 时间:2024/05/16 07:18
问题概述:空间上有很多点,现在要用一个凸多边形将所有点全部包住,求哪些点在这个凸多边形上
输入样例: 对应输出:
4 0 0
0 0 2 3
1 1 3 0
2 3
3 0
分治法(时间复杂度nlogn):
原理:将一个大问题分成几个结构相同的子问题,再把子问题再分成几个更小的子问题…….然后我们就能用递归的
方法,分别求这些子问题的解,最后把每个子问题的解"组装"成原来大问题的解
步骤:
1、把所有的点都放在二维坐标系里面,那么横坐标最小和最大的两个点P1和Pn一定是凸包上的点,这样点集就被分
成了两部分,即X轴的上面和下面,它们分别叫做上包和下包
2、对上包求距离直线P1Pn最远的点Pmax,对下包一样处理
3、作直线P1Pmax、PnPmax,把直线P1Pmax左侧的点当成是上包,把直线PnPmax右侧的点也当成是上包,对下
包一样处理
4、重复步骤2、3直到上方没有点
#include<stdio.h>#include<limits.h>#include<string.h>typedef struct{int x;int y;int temp;/*若这点在凸包上,则temp==1,否则temp==0*/}Point;Point s[105];int n;void Sechup(int a, int b);void Sechdown(int a, int b);int main(void){int T, i, a, b, ax, bx;scanf("%d", &T);while(T--){memset(s, 0, sizeof(s));ax = INT_MAX;bx = INT_MIN;scanf("%d", &n);for(i=1;i<=n;i++){scanf("%d%d", &s[i].x, &s[i].y);if(s[i].x<ax)ax = s[i].x, a = i;if(s[i].x>bx)bx = s[i].x, b = i;}s[a].temp = s[b].temp = 1;Sechup(a, b);/*上包递归*/Sechdown(a, b);/*下包递归*/for(i=1;i<=n;i++){if(s[i].temp==1)printf("%d %d\n", s[i].x, s[i].y);}}return 0;}/*若向量叉乘为负,说明点在直线下面,否则在直线上面(参照直线方向为从左到右)*/void Sechup(int a, int b){int i, max, c;max = 0;for(i=1;i<=n;i++){if((s[b].x-s[a].x)*(s[i].y-s[a].y)-(s[b].y-s[a].y)*(s[i].x-s[a].x)>max){max = (s[b].x-s[a].x)*(s[i].y-s[a].y)-(s[b].y-s[a].y)*(s[i].x-s[a].x);c = i;/*用向量叉乘求三点三角形面积,使三角形面积最大的那个(非直线上的)点便是离参照直线最远的点Pmax*/}}if(max!=0)/*参照直线上方有点*/{s[c].temp = 1;Sechup(a, c);Sechup(c, b);}}void Sechdown(int a, int b){int i, max, c;max = 0;for(i=1;i<=n;i++){if((s[b].x-s[a].x)*(s[i].y-s[a].y)-(s[b].y-s[a].y)*(s[i].x-s[a].x)<max){max = (s[b].x-s[a].x)*(s[i].y-s[a].y)-(s[b].y-s[a].y)*(s[i].x-s[a].x);c = i;}}if(max!=0){s[c].temp = 1;Sechdown(a, c);Sechdown(c, b);}}
Graham扫描法(时间复杂度nlogn):
步骤:
1、找出y值最小(若y值同等最小,取x小的那个)的作为原点P1
2、以P1为坐标原点,将所有点按相对于P0的幅角(连接原点与x轴的夹角大小)从小到大排序,若幅角相同则按与原
点的距离从小到大排序,并依次给点标记P2、P3……Pn
3、初始点P1和第二个点P2入队列,设P3是当前点
4、设当前队伍尾端的点A(x1, y1),队伍尾端倒数第二个点B(x2, y2)和当前点C(x3, y3),求向量AB与向量AC的叉
乘,若为正,则说明点A不在凸包上,将点A踢出队列,执行步骤5,否则说明点在凸包上,执行步骤6
5、当前点仍不变,继续执行步骤4
6、当前点入队,将下一个点作为当前点,执行步骤4,直到所有点全部遍历完毕(最后一个点Pn入队)
#include<stdio.h>#include<limits.h>#include<stdlib.h>#include<string.h>#include<deque>#include<algorithm>using namespace std;typedef struct{int x;int y;}Point;int n, temp;Point top1, top2, s[105];deque<Point> q;bool comp2(Point a, Point b)/*按幅角排序*/{if((a.x-top1.x)*(b.y-top1.y)-(a.y-top1.y)*(b.x-top1.x)>0)return 1;else if((a.x-top1.x)*(b.y-top1.y)-(a.y-top1.y)*(b.x-top1.x)==0 && abs(a.x-top1.x)<abs(b.x-top1.x))return 1;return 0;}int main(void){int T, i, ax, ay;scanf("%d", &T);while(T--){ax = ay = INT_MAX;scanf("%d", &n);for(i=1;i<=n;i++){scanf("%d%d", &s[i].x, &s[i].y);if(s[i].y<ay || s[i].y==ay && s[i].x<ax)temp = i, ay = s[i].y, ax = s[i].x;/*步骤1*/}top1 = s[temp];sort(s+1, s+n+1, comp2);q.push_back(s[1]);q.push_back(s[2]);temp = 3;/*步骤3*/while(temp<=n){top1 = q.back();q.pop_back();/*临时弹出用作判定*/top2 = q.back();if((top2.x-top1.x)*(s[temp].y-top1.y)-(top2.y-top1.y)*(s[temp].x-top1.x)<=0)/*步骤4*/{q.push_back(top1);/*符合条件,临时弹出的归队*/q.push_back(s[temp]);/*当前点入队*/temp++;/*下一个点作为当前点*/}/*不符合条件*/}while(q.empty()==0){top1 = q.back();printf("%d %d\n", top1.x, top1.y);q.pop_back();}}return 0;}
- 凸包模板(分治 or Graham扫描法)
- 凸包问题(Graham扫描法)
- 寻找凸包(Graham扫描法)
- 凸包问题(Graham扫描法)
- Graham扫描法(凸包)
- 二维凸包模板 【Graham扫描算法】
- 凸包graham扫描法
- 凸包 Graham扫描法
- 凸包--Graham扫描法
- POJ1113 Wall 凸包(Graham扫描法)
- 学习凸包(四):Graham 扫描法
- POJ 2187 Beauty Contest(凸包-Graham扫描法)
- HDU 5251 矩形面积(凸包-Graham扫描法)
- matlab练习程序(寻找凸包,Graham扫描法)
- 7凸包问题(Graham扫描法)
- 凸包问题的Graham扫描法
- 寻找凸包的graham 扫描法
- 寻找凸包-graham扫描法
- HDU 1049 Climbing Worm 水题
- Spring Web Flow
- strcpy实现
- jquery点击“遇到问题”隐藏和展现更多文字
- React Native 之安装过程及遇到的问题
- 凸包模板(分治 or Graham扫描法)
- java初级之7数据类型转换
- 41 数组常用函数
- java Scanner类
- tjut 1394
- Uva 11427 Expect the Expected 概率dp 求数学期望
- tomcat中部署静态文件
- Spring 使用Cache
- [iOS开发]日常需求七:UITableView使用的一些小tips