uvalive4838(凸包+重心)

题意:

给出一个n边形,我们要输出有多少种摆放方案使得这个多边形能够稳定摆放(如果重心落在边的端点上,不能稳固)。


思路:

用这n个点围成一个凸包,每次用凸包的一个边当做底边,判断重心是否落在这条边的端点上或者落在边的外面即可。

注意:一定要用初始的n边形求重心,不能用凸包求重心,因为这个我们WA了三个小时。


代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=500005*2;
//const double pi=atan(1.0)*4;
const double eps = 1e-8;
int cmp(double x) {
	if(fabs(x) < eps) return 0;
	if(x > 0) return 1;
	return -1;
}
struct node{
    double x,y;
}e[maxn],res[maxn];
int cmp1(node a,node b)
{
    if(cmp(a.x-b.x) == 0) return cmp(a.y-b.y) < 0;
    return cmp(a.x-b.x)<0;
}
double cross(node a,node b,node c)//向量积
{
    return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);
}
int convex(int n)//求凸包上的点
{
    sort(e,e+n,cmp1);
    int m=0,i,j,k;
    for(i=0;i<n;i++)
    {
        while(m>1&&cmp(cross(res[m-1],e[i],res[m-2]))<=0)m--;
        res[m++]=e[i];
    }
    k=m;
    for(i=n-2;i>=0;i--)
    {
        while(m>k&&cmp(cross(res[m-1],e[i],res[m-2]))<=0)m--;
        res[m++]=e[i];
    }
    if(n>1)m--;
    return m;
}

struct point {
	double x, y;
	point() {};
	point(double a, double b) : x(a), y(b) {};
	friend point operator + (const point & a, const point &b) {
		return point(a.x + b.x , a.y + b.y );
	}
	friend point operator - (const point & a, const point &b) {
		return point(a.x - b.x, a.y - b.y);
	}
	friend point operator * (const point & a, const double &b) {
		return point(a.x * b, a.y * b);
	}
	friend point operator / (const point & a, const double &b) {
		return point(a.x / (b+eps), a.y / (b + eps));
	}
};

double det(const point &a,const point &b) {
	return a.x * b.y - a.y * b.x;
}

struct polygon {
	int n;
	point a[maxn];
	polygon() {};
	double area() {
//	    printf("nnnnnnnnnnnnnnnnnnnnnnnn%d\n", n);
		double sum = 0;
		a[n] = a[0];
		for(int i = 0; i < n; i++) {
//            puts("JJJJJ");
			sum += det(a[i + 1], a[i]);

		}
		return sum / 2;
	}
	point center() {
		point ans = point(0, 0);
//		printf("a = %lf\n",area());
		if(cmp(area()) == 0) return ans;
		a[n] = a[0];
		for(int i = 0; i < n; i++) {
			ans = ans +(a[i] + a[i + 1]) * det(a[i + 1], a[i]);
		}
		return ans / area() / 6.0;
	}
};

polygon p1;
polygon p2;
double dot(point a, point b) {
    return a.x * b.x + a.y * b.y;
}
void PointPro(point p,point s,point t,point &cp) {
    double r = dot((t - s),(p - s))/dot(t-s,t - s);
    cp = s +  (( t - s) * r);
}

bool On(point p, point s, point t) {
    if(cmp(p.x - s.x) == 0 && cmp(p.y - s.y) == 0) return false;
    if(cmp(p.x - t.x) == 0 && cmp(p.y - t.y) == 0) return false;
    return cmp(det(p-s, t - s)) == 0&& cmp(dot(p-s,p-t))<=0;
}

int main()
{
//    freopen("a.txt","r",stdin);
    int T,n,l;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i = 0; i < n; i++){
            cin >> e[i].x >> e[i].y;
//            e[i].x *= 1000;
//            e[i].y *= 1000;
			p2.a[i]=point(e[i].x*1.0,e[i].y*1.0);
        }
		p2.n=n;
		point p0 = p2.center();

        int m=0;
        m=convex(n);
//        if(m == 2) {
//            if(cmp(res[0].x - res[1].x) == 0 && cmp(res[0].y - res[1].y) == 0 ) {
//                printf("0\n");
//                continue;
//            }
//            else{
//                printf("2\n");
//                continue;
//            }
//        }
        int _ans = 0;
        p1.n = m;
//        printf("p1.n = %d\n", p1.n);
        for(int i = 0; i < m; i++) {
            p1.a[i] = point(res[i].x * 1.0 , res[i].y * 1.0 );
        }
//        for(int i = 0; i < m; i++) {
//            printf("%lf %lf\n", p1.a[i].x , p1.a[i].y );
//        }
//        printf("p1.n = %d\n", p1.n);
        
//        printf("%lf %lf\n", p0.x, p0.y);
        for(int i = 0; i < m; i++){
            point jiaodian;
            PointPro(p0, p1.a[i], p1.a[(i + 1) % m], jiaodian);
            if(On(jiaodian, p1.a[i], p1.a[(i+1)%m])) {
                _ans++;
            }
//            printf("jiaod = %lf  %lf   %d\n", jiaodian.x, jiaodian.y,_ans);
        }
        printf("%d\n", _ans);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值