目录
圈奶牛
题目描述
农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏。他建造的围栏必须包括他的奶牛喜欢吃草的所有地点。对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度。
输入格式
输入数据的第一行是一个整数。表示农夫约翰想要围住的放牧点的数目 n。
第 2 到第 (n+1) 行,每行两个实数,第 (i+1) 行的实数 xi,yi 分别代表第 i 个放牧点的横纵坐标。
输出格式
输出输出一行一个四舍五入保留两位小数的实数,代表围栏的长度。
输入输出样例
输入
4
4 8
4 12
5 9.3
7 8
输出
12.00
说明/提示
数据规模与约定
对于 100% 的数据,保证 1≤n≤10^5,−10^6≤xi,yi≤10^6。小数点后最多有 2 位数字。
代码展示:
Graham版
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n;
struct Node{
double x,y;
}p[N],stk[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)
{
double x0=p[1].x,y0=p[1].y;
double det=(a.x-x0)*(b.y-y0)-(a.y-y0)*(b.x-x0);
if(det!=0)
return det>0;
return dis(a,p[1])<dis(b,p[1]);
}
double cross(Node a,Node b,Node c)
{
return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>p[i].x>>p[i].y;
int idx=1;
for(int i=1;i<=n;i++)
{
if(p[i].y<p[idx].y)
idx=i;
else if(p[i].y==p[idx].y&&p[i].x<p[idx].x)
idx=i;
}
swap(p[idx],p[1]);
sort(p+2,p+n+1,cmp);
p[n+1]=p[1];
int top=0;
for(int i=1;i<=n+1;i++)
{
while(top>1&&cross(stk[top-1],stk[top],p[i])<0)
top--;
stk[++top]=p[i];
}
double res=0;
for(int i=1;i<top;i++)
res+=dis(stk[i],stk[i+1]);
cout<<fixed<<setprecision(2)<<res;
return 0;
}
Andrew版
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n;
struct Node{
double x,y;
}p[N],stk[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)
{
return a.x!=b.x? a.x<b.x : a.y<b.y;
}
double cross(Node a,Node b,Node c)
{
return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>p[i].x>>p[i].y;
sort(p+1,p+n+1,cmp);
int top=0;
for(int i=1;i<=n;i++)
{
while(top>1&&cross(stk[top-1],stk[top],p[i])<=0)
top--;
stk[++top]=p[i];
}
int t=top;
for(int i=n-1;i>=1;i--)
{
while(top>t&&cross(stk[top-1],stk[top],p[i])<=0)
top--;
stk[++top]=p[i];
}
double res=0;
for(int i=1;i<top;i++)
res+=dis(stk[i],stk[i+1]);
cout<<fixed<<setprecision(2)<<res;
return 0;
}