Poj Wall(凸包)

这篇博客介绍了如何使用凸包算法解决在给定距离限制下,建造环绕城堡最小围墙长度的问题。通过计算点的凸包,并结合点乘公式计算弧长,最终得出最小围墙总长度。代码中展示了具体的实现过程,包括读取多边形顶点、构造凸包、计算弧长等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • Wall
  • 题意
    已知一个多边形的城堡,现在用用最少的石头建造环绕城堡的城墙,但是城墙不能离城堡超过一定的距离L。问这个城墙最小的长度。
  • 思路
    首先知道,对于一条边,我们只需将它往外平移L个长度即可,至于顶点肯定做一个半径为L的圆(一部分)将两边连接起来,如果该顶点是一个凹点,那肯定没有将两边的点直接相连短,所以需要先构造凸包(如果不知道为什么要构造凸包,可以画一下,很好看出来)。至于圆弧的那部分,需要计算角度,容易知道图中角度1和角度2互补,先将角度2利用点乘公式(不能用叉乘,因为用asin函数一个值对应两个角度)计算出来,就知道角度1了。构造凸包的算法以及模板代码中参考《挑战程序与设计竞赛》
    在这里插入图片描述
  • 代码
#pragma GCC optimize(2)
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

typedef long long ll;
typedef unsigned long ul;
typedef unsigned long long ull;
#define pi acos(-1.0)
#define e exp(1.0)
#define pb push_back
#define mk make_pair
#define fir first
#define sec second
#define scf scanf
#define prf printf
typedef pair<ll,ll> pa;
const int dir_4[4][2]={-1,0,0,1,1,0,0,-1};
const int dir_8[8][2]={-1,-1,-1,0,-1,1,0,1,1,1,1,0,1,-1,0,-1};
const ll INF=0x3f3f3f3f3f3f3f3f;
const double eps=1e-8;
const int MAX_N=1e3+7;
double add(double a,double b){
	if(fabs(a+b)<eps)
	return 0;
	return a+b;
}
struct P{
	double x,y;
	P(){}
	P(double x,double y):x(x),y(y){}
	P operator+(P p){
		return P(add(x,p.x),add(y,p.y));
	}
	P operator-(P p){
		return P(add(x,-p.x),add(y,-p.y));
	}
	P operator*(double d){
		return P(x*d,y*d);
	}
	double dot(P p){//点乘 
		return add(x*p.x,y*p.y);
	}
	double det(P p){//叉乘 
		return add(x*p.y,-y*p.x);
	}
	bool operator<(const P &p)const{
		if(x!=p.x)
		return x<p.x;
		return y<p.y;
	}
	double dis(P p){
		return sqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y));
	}
}pos[MAX_N],pos_hull[MAX_N];
double L;
int N,cnt;
int main()
{
//  freopen(".../.txt","w",stdout);
//  freopen(".../.txt","r",stdin);
//	ios::sync_with_stdio(false);
	int i,j,k;
	scf("%d %lf",&N,&L);
	for(i=0;i<N;i++){
		scf("%lf %lf",&pos[i].x,&pos[i].y);
	}
	sort(pos,pos+N);
	cnt=0;
	for(i=0;i<N;i++){//构造凸包的下链 
		while(cnt>1&&(pos_hull[cnt-1]-pos_hull[cnt-2]).det(pos[i]-pos_hull[cnt-1])<=0)
		cnt--;
		pos_hull[cnt++]=pos[i];
	}
	k=cnt;
	for(i=N-2;i>=0;i--){//构造凸包的上链 
		while(cnt>k&&(pos_hull[cnt-1]-pos_hull[cnt-2]).det(pos[i]-pos_hull[cnt-1])<=0)
		cnt--;
		pos_hull[cnt++]=pos[i];
	}
	cnt--;
	double res=0;
	//a*b*cos
	for(i=0;i<cnt;i++){
		double dis1=pos_hull[i].dis(pos_hull[(i-1+cnt)%cnt]);//b
		double dis2=pos_hull[i].dis(pos_hull[(i+1)%cnt]);//a
		res+=dis2;//加上平移的边的长度 
		res+=(pi-acos((pos_hull[(i+1)%cnt]-pos_hull[i]).dot(pos_hull[(i-1+cnt)%cnt]-pos_hull[i])/dis1/dis2))*L;//加上弧长 
	}
	prf("%.0f\n",res);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值