poj 3348(求凸包面积)

题意:一片草地上有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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值