题目链接:poj 1113
参考博客:https://www.cnblogs.com/kuangbin/archive/2012/04/13/2445633.html
https://www.cnblogs.com/acgoto/p/9547049.html
题意:给出n个点,让你把这n个点围起来,有个前提,围墙到顶点的距离要等于L,问围墙有多长。
题解搬kuangbin神犇的。
题解:这道题的答案是凸包周长加上一个圆周长,即包围凸包的一个圆角多边形,但是没弄明白那些圆角加起来为什么恰好是一个圆。每个圆角是以凸包对应的顶点为圆心,给定的L为半径,与相邻两条边的切点之间的一段圆弧。每个圆弧的两条半径夹角与对应的凸包的内角互补。假设凸包有n条边,则所有圆弧角之和为180°*n-180°*(n-2)=360°。故,围墙周长为=n条平行于凸包的线段+n条圆弧的长度=凸包周长+围墙离城堡距离L为半径的圆周长。
代码:
andrew算法和graham算法求凸包,紫薯上说andrew更快,数值稳定性更好,因为andrew算法只是按照坐标排序,不同于graham算法,是按极角排序,大量用叉积比较。
///andrew 求凸包 首尾相同
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=1010;
const double PI=acos(-1.0);
struct point{
int x,y;
point(){}
point(int _x,int _y){
x=_x;y=_y;
}
}p[maxn],ch[maxn];
point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);}
point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}
point operator * (point a,int p) { return point(a.x*p,a.y*p);}
point operator / (point a,int p){ return point(a.x/p,a.y/p);}
bool operator < (const point &a,const point &b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double esp=1e-8;
int dcmp(double x){
if(fabs(x)<esp) return 0;
else return x<0?-1:1;
}
bool operator ==(const point &a,const point &b){
return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
int Cross(point a,point b) { return a.x*b.y-a.y*b.x;}
double Length(point a) { return sqrt(a.x*a.x*1.0+a.y*a.y*1.0);}
bool cmp(point a,point b) ///坐标排序
{
return (a.y<b.y||(a.y==b.y&&a.x<b.x));
}
int tot;
void andrew(int n)
{
sort(p,p+n,cmp);
tot=-1;
for(int i=0;i<n;i++) ///构造凸包下侧
{
while(tot>0&&Cross(ch[tot]-ch[tot-1],p[i]-ch[tot-1])<=0)
tot--;
ch[++tot]=p[i];
}
for(int i=n-2,k=tot;i>=0;i--){ ///构造凸包上侧
while(tot>k&&Cross(ch[tot]-ch[tot-1],p[i]-ch[tot-1])<=0)
tot--;
ch[++tot]=p[i];
}
}
int main()
{
int N,L;
while(~scanf("%d%d",&N,&L))
{
for(int i=0;i<N;i++)
{
scanf("%d%d",&p[i].x,&p[i].y);
}
andrew(N);
double sum=0;
for(int i=0;i<tot;i++){
sum+=Length(ch[i+1]-ch[i]);
}
sum+=Length(ch[tot]-ch[0]);
sum+=2*PI*L;
printf("%d\n",(int)(sum+0.5));
}
return 0;
}
///graham求凸包 首尾不同
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=1010;
const double PI=acos(-1.0);
struct point{
int x,y;
point(){}
point(int _x,int _y){
x=_x;y=_y;
}
}node[maxn];
point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);}
point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}
point operator * (point a,int p) { return point(a.x*p,a.y*p);}
point operator / (point a,int p){ return point(a.x/p,a.y/p);}
bool operator < (const point &a,const point &b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double esp=1e-8;
int dcmp(double x){
if(fabs(x)<esp) return 0;
else return x<0?-1:1;
}
bool operator ==(const point &a,const point &b){
return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
int Cross(point a,point b) { return a.x*b.y-a.y*b.x;}
double Length(point a) { return sqrt(a.x*a.x+a.y*a.y);}
point p0; ///以p0为根据
bool cmp(point a,point b) ///极角排序函数,角度相同则距离小的在前面
{
int tmp=Cross(a-p0,b-p0);
if(tmp>0) return true;
else if(tmp==0&&dcmp(Length(a-p0)-Length(b-p0))<0)
return true;
else return false;
}
int num[maxn],tot;
void graham(int n)
{
tot=0;
if(n==1){
tot=0;num[0]=0;
}
if(n==2){
tot=1;num[0]=0;num[1]=1;
}
if(n>2){
tot=1;num[0]=0;num[1]=1;
for(int i=2;i<n;i++)
{
while(tot>0&&Cross(node[num[tot]]-node[num[tot-1]],node[i]-node[num[tot-1]])<=0)
tot--;
num[++tot]=i;
}
}
}
int main()
{
int N,L;
while(~scanf("%d%d",&N,&L))
{
scanf("%d%d",&node[0].x,&node[0].y);
int k=0;
p0=point(node[0].x,node[0].y);
for(int i=1;i<N;i++)
{
scanf("%d%d",&node[i].x,&node[i].y);
if(p0.y>node[i].y||((p0.y==node[i].y)&&(p0.x>node[i].x))){
p0=node[i];
k=i;
}
}
node[k]=node[0];
node[0]=p0;
sort(node+1,node+N,cmp);
graham(N);
double sum=0;
for(int i=0;i<tot;i++){
sum+=Length(node[num[i]]-node[num[i+1]]);
}
sum+=Length(node[num[tot]]-node[num[0]]);
sum+=2*PI*L;
printf("%d\n",(int)(sum+0.5));
}
return 0;
}