PojWall(凸包)

it2026-04-15  2

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; }
最新回复(0)