hihocoder 1083 积分,计算几何

hihocoder 1083

描述

在平面上有一个顶点数为N的多边形P,区域

14183628378090.gif

你需要写一个程序计算这个积分

14183628709197.gif

输入

输入包含T (T<=500)个测试用例。数字T在输入文件的第一行给出。每个测试用例的第一行是一个整数N代表多边形的点数。其后跟随N行,每行包含两个点Xi和Yi,表示第i个点的坐标,当我们以给定的顺序连接这些点,我们得到了一个多边形。题目保证多边形不自交,这个多边形的面积也不会是零,也不会出现3个相邻的点共线的情况。

【参数说明】

3 <= N <= 8000

|Xi|, |Yi| <= 20000

输出

对于每个测试用例行输出结果占一行。将答案四舍五入到小数点后两位(0.005四舍五入到0.01)。

解题

这个题目主要的点在于这个重积分式子可以变形。

重心公式= xg=DxdxdyDdxdy,yg=DydxdyDdxdy x g = ∬ D x d x d y ∬ D d x d y , y g = ∬ D y d x d y ∬ D d x d y

so,这里:

D(x+y)dxdy=Dxdxdy+Dydxdy=(xg+yg)s ∬ D ( x + y ) d x d y = ∬ D x d x d y + ∬ D y d x d y = ( x g + y g ) s ,s自然是这个多边形的面积。

求解三角形重心: (xp0+xp1+xp2)/3=xg ( x p 0 + x p 1 + x p 2 ) / 3 = x g

​ ​ ​ ​ ​ ​ ​ ​  (yp0+yp1+yp2)/3=yg ( y p 0 + y p 1 + y p 2 ) / 3 = y g

要求的就变成了重心,求多边形的重心不好处理,但是我们分割多边形成多个三角形,因为这个多边形是可以为凹多边形,所以应该用叉积求面积,这样的面积有方向性, 可以抵消凹多边形带来的问题,最后要判断这个这个多边形面积总和的方向性,因为如果最后的面积是负数,说明我们得到的答案是最终答案的负数。就要取反。

代码

#include <bits/stdc++.h>
using namespace std;
struct Point{
    double x,y;
    Point(double x,double y):x(x),y(y){}
    Point(){}
};
typedef Point Vector;
Point operator+(Point a,Point b){return Point(a.x+b.x,a.y+b.y);}
Point operator-(Point a,Point b){return Point(a.x-b.x,a.y-b.y);}
Point operator*(Point a,double D){return Point(a.x*D,a.y*D);}
Point operator/(Point a,double D){return Point(a.x/D,a.y/D);}
bool operator < (const Point &a, const Point & b){return a.x < b.x || (a.x == b.x && a.y < b.y);}
const double eps=1e-10;
int dcmp(double x){if(fabs(x)<eps) return 0; else return x<0?-1:1;}
bool operator==(const Point& a,const Point& b){return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;}
/*
 dot        向量间的点积
 length     向量的模
 angle      向量间的夹角弧度
 cross      向量间的叉积
 area2      三点围成三角形有向面积的两倍
 rotate     向量绕起点逆时针旋转一定弧度后的向量
 normal     求向量的单位法线
 torad      角度化弧度
*/
double dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
double length(Vector a){return sqrt(dot(a,a));}
double angle(Vector a,Vector b){return acos( dot(a,b)/length(a)/length(b) );}
double angle(Vector a){return atan2(a.y,a.x);}
double cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
double area2(Point A,Point B,Point C){return cross(B-A,C-A);}
Vector rotate(Vector a,double rad){
  return Vector(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));
}
Vector normal(Vector a){double l=length(a);return Vector(-a.y/l,a.x/l);}
double torad(double deg){
    return deg/180 * M_PI;
}
int convexHull(Point *p,int n,Point* ch) {
  sort(p,p+n);
  int m=0;
  for(int i=0;i<n;i++){
    while(m>1&&dcmp(cross(ch[m-1]-ch[m-2],p[i]-ch[m-2] ))<=0 )m--;
    ch[m++]=p[i];
  }
  int k=m;
  for(int i=n-2;i>=0;i--) {
    while(m>k&&dcmp(cross(ch[m-1]-ch[m-2],p[i]-ch[m-2]))<=0)m--;
    ch[m++]=p[i];
  }
  if(n>1)m--;
  return m;
}
const int maxn = 8000+10;
Point po[maxn];

double countfun(Point p0,Point p1,Point p2)
{
    double s = area2(p0,p1,p2)/2;
    double xg = (p1.x + p0.x + p2.x) / 3.0;
    double yg = (p1.y + p0.y + p2.y) / 3.0;
    return (xg+yg)*s;

}
int main()
{
    freopen("in.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--) {
        int x,y,n;
        scanf("%d",&n);
        for(int _=0;_<n;_++ )
            scanf("%lf%lf",&po[_].x,&po[_].y);
        double ans = 0;
        double s = 0;
        for(int i=1;i<n-1;i++) {
            ans+=countfun(po[0],po[i],po[i+1]);
            s+=area2(po[0],po[i],po[i+1])/2;
        }
        if(s<0) ans=-ans;
        cout << fixed << setprecision(2) << ans << endl;
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值