P2742 [USACO5.1]圈奶牛Fencing the Cows /【模板】二维凸包
题意:n个点,求凸包周长。
解决这类问题有专门的算法:Graham算法和Andrew算法
网上有这两个算法的图解,很清晰,Andrew是Graham扫描算法的变种,和Graham相比,Andrew更快,且更稳定,所以主要讲一下Andrew。
Graham算法我只懂原理,代码没仔细看。
Andrew算法模板:
#define inf 0x3f3f3f3f;
const int N=1e4+7;
int n;
double sum=0.0;
struct node{
double x,y;
}p[N],s[N];
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 cmp(node a,node b){
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
double getk(node a,node b){
if(a.x==b.x) return inf;
return (b.y-a.y)/(b.x-a.x);
}
void andrew(){
sort(p+1,p+1+n,cmp);
int cnt,tot; cnt=tot=0;
for(int i=1;i<=n;i++){
s[++cnt]=p[i];
while(cnt>2&&getk(s[cnt-2],s[cnt])<getk(s[cnt-2],s[cnt-1]))
s[cnt-1]=s[cnt],cnt--;
}
for(int i=1;i<cnt;i++) sum+=dis(s[i],s[i+1]);
tot=cnt; cnt=0;
for(int i=n;i;i--){
s[++cnt]=p[i];
while(cnt>2&&getk(s[cnt-2],s[cnt])<getk(s[cnt-2],s[cnt-1]))
s[cnt-1]=s[cnt],cnt--;
}
for(int i=1;i<cnt;i++) sum+=dis(s[i],s[i+1]);
tot=tot+cnt-2;
//tot为凸包上点的个数
// printf("%d\n",tot);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>p[i].x>>p[i].y;
andrew();
printf("%.2lf",sum);
}
/*
4
4 8
4 12
5 9.3
7 8
12.00
*/