题解 P2742 【[USACO5.1]圈奶牛Fencing the Cows】
Great_Influence · · 题解
方法是一样的,先求凸包,再算距离。但是我的程序比一般的有点不同。在算凸包时,我选择计算两点间角度差再做比较(就是下面的sita),其他地方基本与标程一样。这样算的话挺好理解的。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const double Pi=3.1415926535898;
const int MAXN=10000+100;
bool nf[MAXN];
int n,c[MAXN];
struct cow
{
double x,y;
}a[MAXN];//存牛的坐标
double sita(double x,double y)//计算角度,用的是弧度制,注意负角的处理
{
double rou=sqrt(x*x+y*y);
x/=rou;
y/=rou;
double s=acos(x);
if(y>=0)return s;
else return -s;
}
bool cmp(cow a,cow b)//sort函数比较
{
return a.x<b.x||a.x==b.x&&a.y<b.y;
}
double dis(int x,int y)//求距离
{
return sqrt((a[x].x-a[y].x)*(a[x].x-a[y].x)+(a[x].y-a[y].y)*(a[x].y-a[y].y));
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
sort(a+1,a+n+1,cmp);
int f=1;
c[1]=1;
int h=1,next;
double angle;
while(h!=n)
{
angle=3*Pi;
next=0;
for(int i=h+1;i<=n;i++)if(sita(a[i].x-a[h].x,a[i].y-a[h].y)<angle)//循环找倾斜角最小的边(倾斜角可为负数,虽然不严谨)
{
angle=sita(a[i].x-a[h].x,a[i].y-a[h].y);
next=i;
}
c[++f]=next;
nf[next]=true;
h=next;
}
while(h!=1)//反过来再求一遍凸包
{
angle=3*Pi;
next=0;
for(int i=h-1;i>=1;i--)if(!nf[i]&&sita(a[h].x-a[i].x,a[h].y-a[i].y)<angle)
{
angle=sita(a[h].x-a[i].x,a[h].y-a[i].y);
next=i;
}
c[++f]=next;
h=next;
}
double sum=0.0;
for(int i=1;i<f;i++)sum+=dis(c[i],c[i+1]);//求距离
printf("%.2lf\n",sum);
return 0;
}