#凸包#洛谷 2116 城墙 题目 分析 代码

有一次,一个贪婪的国王命令他的骑士在他的城堡外修建一堵围墙,要求围墙离城堡的最近距离不能少于 (L)

城堡是一个 (n) 边形,国王非常吝啬,不愿意多花建一米的围墙,多建的话他会杀掉负责修建的骑士。

请你帮助这个倒霉的骑士,帮他求出最少需要修建多长的围墙。


分析

不愿多建那就是建一个凸包是最优的,
然后最近距离不能少于(L),那么也就是往外扩一圈,
也就是凸包的周长加上半径为(L)的圆


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#define rr register
#define p(x) ((x)*(x))
#define cj(i,j,k) ((i.x-k.x)*(j.y-k.y)-(j.x-k.x)*(i.y-k.y))
#define dis(i,j) sqrt(p(i.x-j.x)+p(i.y-j.y))
using namespace std;
struct site{double x,y;}a[1011];
int n,k,zh[1011],len,l; double ans;
bool cmp(site i,site j){
	rr double t=cj(i,j,a[1]);
	return t>0||(!t&&dis(i,a[1])<dis(j,a[1]));
}
signed main(){
	scanf("%d%d",&n,&l); k=1;
	for (rr int i=1;i<=n;++i){
		scanf("%lf%lf",&a[i].x,&a[i].y);
		if (a[i].y<a[k].y||(a[i].y==a[k].y&&a[i].x<a[k].x)) k=i;
	}
	swap(a[1],a[k]); sort(a+2,a+1+n,cmp);
	zh[1]=1; zh[2]=2; zh[3]=3; len=3;
	for (rr int i=4;i<=n;++i){
		while (cj(a[i],a[zh[len]],a[zh[len-1]])>=0) --len;
		zh[++len]=i;
	}
	for (rr int i=1;i<len;++i) ans+=dis(a[zh[i]],a[zh[i+1]]);
	return !printf("%.lf",ans+dis(a[zh[1]],a[zh[len]])+2.0*acos(-1.0)*l);
}