凸包(2021.8.18-2021.8.19)

参考博客:点击Here
步骤
1.先对坐标进行排序,找到最下面的点(y值最小的);
如果有多个,选取横坐标最小的点,将其存入栈中(第一个点)
2.对其他坐标按照极角从小到大进行排序,
极角相同,只留下与P0最远的那个
3.将按极角大小排序后的第一个点存入栈中,
再依次遍历其他点,
如果栈顶俩个元素P1,P2与该点C满足:
P2P1 ✖ P2C > 0 ,说明左转,否则弹出栈顶(右转),
C入栈
4.再用栈顶前俩元素和下一点判断,直到判断完所有点
5.最后计算凸包俩点之间距离求和输出
练习:题目链接

#include<iostream>
#include<string.h> 
#include<algorithm>
#include<math.h>
using namespace std;

struct node{
	int x,y;//存点的坐标 
};
const int maxn=1e3+5; 
node vex[maxn];//题目给出的坐标 
node stackk[maxn];//凸包中所有的点 

bool cmp1(node a,node b){//排序找第一个点 
	if(a.y==b.y){
		return a.x<b.x;
	}
	return a.y<b.y;
} 

int cross(node a,node b,node c){//计算叉乘 
	return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}

double dis(node a,node b){//计算距离 
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
} 


bool cmp2(node a,node b){//极角排序 (妙啊!)
	int m=cross(vex[0],a,b);
	if(m>0)
		return 1;
	else if(m==0&&(dis(vex[0],a)-dis(vex[0],b)<=0))
		return 1;
	else
		return 0; 
}


int main(){
	int t;
	cin>>t;
	for(int i=0;i<t;i++){
		cin>>vex[i].x>>vex[i].y;
	}
	if(t==1){
		cout<<0.00<<endl;
	}
	else if(t==2){
		printf("%.2f",dis(vex[0],vex[1]));
	} 
	else{
		memset(stackk,0,sizeof(stackk));
		sort(vex,vex+t,cmp1);
		stackk[0]=vex[0];
		sort(vex+1,vex+t,cmp2);
		stackk[1]=vex[1];//将排序后的第一个点入栈
		int top=1;
		for(int i=2;i<t;i++){
			
			while(cross(stackk[top-1],stackk[top],vex[i])<0){//while
				--top;
			}
			
			stackk[++top]=vex[i];
		} 
		
		double s=0;//计算凸包周长 
		for(int i=1;i<=top;i++){
			s+=dis(stackk[i-1],stackk[i]);
		}
		s+=dis(stackk[top],vex[0]);//最后一个点和第一个点之间的距离
		printf("%.2lf\n",s); 
	}
	
	return 0;
}
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用 Graham 扫描算法来解决这个问题。具体步骤如下: 1. 找到所有中 y 坐标最小 P0,如果有多个 y 坐标相同,则选择 x 坐标最小。 2. 将所有按照与 P0 的极角从小到大排序,如果有多个与 P0 的极角相同,则按照距离 P0 的距离从小到大排序。 3. 依次遍历排序后的,对于每个 Pi,如果 Pi、Pi-1 和 Pi-2 组成的向量不是逆时针方向,则将 Pi-1 从凸包中删除。 4. 最后得到的集就是按照逆时针排列的凸包。 根据这个算法,可以得到这些按照逆时针排列的结果为: 244.1821314.34-47.2585 243.6121314.59-54.2359 244.1481314.46-65.125 243.8691314.3-67.8689 242.9171313.88-71.8364 239.6851312.65-78.6564 236.711311.57-82.9158 233.3181310.38-86.6318 228.2821308.62-91.6409 223.9251307.12-94.9972 217.9131305.08-98.6861 209.4181302.27-101.409 201.7231299.79-101.566 194.1541299.61-19.8384 188.2361297.61-23.4317 180.3571294.85-31.5159 178.361294.12-34.3795 174.761292.76-41.8703 172.2181291.74-49.0167 170.9821291.2-54.0538 171.2971291.06-62.7229 172.4011291.28-67.9265 173.7171291.57-72.4188 174.4551291.75-74.6728 176.2711292.21-79.193 178.2681292.74-83.2374 179.8051293.16-85.9282 181.4961293.64-88.2235 186.3561295.05-94.0349 192.4441296.88-98.5715 201.3031301.97-18.1151 205.531303.33-18.1063 213.7331305.95-18.7536 218.3081307.39-20.0781 222.1911308.59-21.9997 225.9841309.74-24.5403 229.7841310.87-27.6483 232.0281311.54-29.8258 234.1151312.15-31.9929 237.1941313.03-35.9478 240.1011313.84-40.4844

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值