题意:一片草地上有n课树,现在你想用绳子圈出一个尽可能大的面积出来养牛。已知每只牛需要50单位的面积,问最多能养几只牛。
解题思路:凸包的面积。这里一般的思路就是先求出凸包,再以最低点为顶点分割n-2个小三角形,这样只需要求n-2个三角形的面积即可。不过这样做可能精度损失有点大。最好的方法就是用向量的叉积,当然要取绝对值。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 10000;
const double eps = 1e-8;
struct Point
{
double x,y;
}p[maxn],Stack[maxn];
int top;
double Cross(Point a,Point b,Point c)
{
return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);
}
double dis(Point a,Point b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int cmp(Point a,Point b) ///设<p1,p2,...pm>为对其余点按以p0为中心的极角逆时针排序所得的点集(如果有多个点有相同的极角,除了距p0最远的点外全部移除)
{
if(Cross(a,b,p[0]) > eps)
return 1;
if(fabs(Cross(a,b,p[0])) < eps && dis(b,p[0])-dis(a,p[0]) > eps)
return 1;
return 0;
}
void Graham(int n)
{
top=2; ///栈顶在2,因为凸包的前两个点是不会变了
sort(p+1,p+n,cmp);
Stack[0]=p[0]; ///压p0p1p2进栈S
Stack[1]=p[1];
Stack[2]=p[2];
for(int i = 3; i < n; i++){
while(top >= 1 && Cross(p[i],Stack[top],Stack[top-1]) > eps){///有了更好的选择
top--;
}
Stack[++top]=p[i];
}
}
double getArea()
{
double sum = fabs(Cross(Stack[1],Stack[2],Stack[0]));
for(int i = 2; i < top; i++)
sum += fabs(Cross(Stack[i],Stack[i+1],Stack[0]));
return sum / 2.0;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i = 0; i < n; i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
if(n < 3)
{
printf("0\n");
continue;
}
int k = 0;
for(int i = 0; i < n; i++) ///令p0为Q中Y-X坐标排序下最小的点
if(p[k].y > p[i].y || ((p[k].y == p[i].y) && (p[k].x > p[i].x)))
k = i;
swap(p[0],p[k]);
Graham(n);
if(top < 3)
{
printf("0\n");
continue;
}
double ans = getArea();
printf("%d\n",(int)ans/50);
}
return 0;
}