HDU_4242_Rancher's Gift(三角形面积)

Rancher's Gift
Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu

Description

Download as PDF

Rancher Joel has a tract of land in the shape of a convex quadrilateral that he wants to divide among his sons Al, Bob, Chas and Dave, who wish to continue ranching on their portions, and his daughter Emily, who wishes to grow vegetables on her portion.

The center of the tract is most suitable for vegetable farming so Joel decides to divide the land by drawing lines from each corner (A, B, C, D in counter clockwise order) to the center of an opposing side (respectively A', B', C' and D' ). Each son would receive one of the triangular sections and Emily would receive the central quadrilateral section. As shown in the figure, Al's tract is to be bounded by the line from A to B, the line from A to the midpoint of BC and the line from B to the midpoint of CD; Bob's tract is to be bounded by the line from B to C, the line from B to the midpoint of CD and the line from C to the midpoint of DA, and so on.

\epsfbox{p5806.eps}

Your job is to write a program that will help Rancher Joel determine the area of each child's tract and the length of the fence he will have to put around Emily's parcel to keep her brothers' cows out of her crops.

For this problem, A will always be at (0, 0) and B will always be at (x, 0). Coordinates will be in rods (a rod is 16.5 feet). The returned areas should be in acres to 3 decimal places (an acre is 160 square rods) and the length of the fence should be in feet, rounded up to the next foot.

Input

The first line of input contains a single integer P, ( 1$ \le$P$ \le$1000), which is the number of data sets that follow. Each data set is a single line that contains of a decimal integer followed by five (5) space separated floating-point values. The first (integer) value is the data set number, N. The floating-point values are B.xC.xC.yD.x and D.y in that order (where V.x indicates the x coordinate of V and V.yindicates the y coordinate of V). Recall that the y coordinate of B is always zero (0).

The supplied coordinates will always specify a valid convex quadrilateral.

Output

For each data set there is a single line of output. It contains the data set number, N, followed by a single space followed by five (5) space separated Itoating point values to three (3) decimal place accuracy, followed by a single space and a decimal integer. The floating-point values are the areas in acres of the properties of Al, Bob, Chas, Dave, and Emily respectively. The final integer is the length of fence infeet required to fence in Emily's property (rounded up to the next foot).

Sample Input

3
1 200 250 150 -50 200
2 200 200 100 0 100
3 201.5 157.3 115.71 -44.2 115.71

Sample Output

1 35.000 54.136 75.469 54.167 54.666 6382
2 25.000 25.000 25.000 25.000 25.000 4589
3 29.144 29.144 29.144 29.144 29.144 4937

题型:计算几何


题意:

           一个农场主要将凸四边形土地分给四个儿子和一个女儿,儿子分别是Al、Bob、Chas、Dave,女儿叫做emily(O_o这名字好。。。),将每个顶点与对边的中点连起来,得到四个三角形按逆时针依次给四个儿子,中间一个空出来的凸四边形则分给女儿,女儿的土地外围需要用篱笆围上。A点总是原点,B点总是在x轴上,输入时输的是Bx、Cx、Cy、Dx、Dy,这样就得到了四个点的坐标,求出四个儿子和女儿的土地的面积(保留三位小数),还有篱笆的长度(int型,向上取整)。


分析:

       我的方法比较果断,硬算。。。

       先将各个边的中点坐标算出,然后用两条直线求交点的方法求出女儿土地的四个定点的坐标(或许直接用向量求三角形的面积也行,但是考虑到要算篱笆长度,还是先将坐标算出来比较好吧)。然后根据公式

                                                     S=|x0y1+x2y0+x1y2-x2y1-x0y2-x1y0| / 2

       求出各个三角型的面积,将凸四边形分成两个三角形开看也能求出女儿的土地面积,再用两点求距离公式来计算篱笆的长度。


注意点:

        不小心的人会发现自己写的好好的代码感觉答案是错的(比如说我尴尬),其实是木有注意到题目中的话,输入与输出的单位是不一致的,要转换一下。再输入中,坐标的单位是rod,输出的面积的单位是acre(亩),而篱笆的单位是feet,1 acre = 160 rod^2 ,1 rod = 16.5 feet。


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
char a[20];

double funx(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4){
    return (y4-y2+(y1-y2)*x2/(x1-x2)-(y3-y4)*x4/(x3-x4))/((y1-y2)/(x1-x2)-(y3-y4)/(x3-x4));
}
double funy(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4){
    return y2+(y1-y2)*(funx(x1,y1,x2,y2,x3,y3,x4,y4)-x2)/(x1-x2);
}

double area(double x0,double y0,double x1,double y1,double x2,double y2){
    return fabs(x0*y1+x2*y0+x1*y2-x2*y1-x0*y2-x1*y0);
}

double dis(double x1,double y1,double x2,double y2){
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

int main(){
    double ax=0.0,ay=0.0,bx,by=0.0,cx,cy,dx,dy;
    double aax,aay,bbx,bby,ccx,ccy,ddx,ddy;
    int t,n;
    while(~scanf("%d",&t)){
        while(t--){
            scanf("%d%lf%lf%lf%lf%lf",&n,&bx,&cx,&cy,&dx,&dy);
            aax=(bx+cx)/2;
            aay=(by+cy)/2;
            bbx=(cx+dx)/2;
            bby=(cy+dy)/2;
            ccx=(ax+dx)/2;
            ccy=(ay+dy)/2;
            ddx=(ax+bx)/2;
            ddy=(ay+by)/2;
            double x1=funx(ax,ay,aax,aay,bx,by,bbx,bby);
            double y1=funy(ax,ay,aax,aay,bx,by,bbx,bby);
            double x2=funx(bx,by,bbx,bby,cx,cy,ccx,ccy);
            double y2=funy(bx,by,bbx,bby,cx,cy,ccx,ccy);
            double x3=funx(cx,cy,ccx,ccy,dx,dy,ddx,ddy);
            double y3=funy(cx,cy,ccx,ccy,dx,dy,ddx,ddy);
            double x4=funx(ax,ay,aax,aay,dx,dy,ddx,ddy);
            double y4=funy(ax,ay,aax,aay,dx,dy,ddx,ddy);
            double al,bob,chas,dave,emily;
            al  =area(ax,ay,bx,by,x1,y1)/2/160;
            bob =area(bx,by,cx,cy,x2,y2)/2/160;
            chas=area(cx,cy,dx,dy,x3,y3)/2/160;
            dave=area(dx,dy,ax,ay,x4,y4)/2/160;
            double all=(area(ax,ay,bx,by,cx,cy)+area(ax,ay,cx,cy,dx,dy))/2/160;
            emily=all-al-bob-chas-dave;
            int d=(int)ceil((dis(x1,y1,x2,y2)+dis(x2,y2,x3,y3)+dis(x3,y3,x4,y4)+dis(x4,y4,x1,y1))*16.5);
            printf("%d %.3f %.3f %.3f %.3f %.3f %d\n",n,al,bob,chas,dave,emily,d);
        }
    }
    return 0;
}

再献上队友26971 B的模板代码,是的,你木有看错,五位数……

→_→我和我的小伙伴们都惊呆了,hp哥教导说:“一行代码七美元”,我说:“呵呵~”得意

此代码内含丰富模板,偷笑供欣赏,供惊叹,供吐槽,供使用,人身安全,切勿模仿。。。

#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#include <stdio.h>
#define MAX_N 100
using namespace std;

int n;

///
//常量区
const double INF        = 1e10;     // 无穷大
const double EPS        = 1e-15;    // 计算精度
const int LEFT          = 0;        // 点在直线左边
const int RIGHT         = 1;        // 点在直线右边
const int ONLINE        = 2;        // 点在直线上
const int CROSS         = 0;        // 两直线相交
const int COLINE        = 1;        // 两直线共线
const int PARALLEL      = 2;        // 两直线平行
const int NOTCOPLANAR   = 3;        // 两直线不共面
const int INSIDE        = 1;        // 点在图形内部
const int OUTSIDE       = 2;        // 点在图形外部
const int BORDER        = 3;        // 点在图形边界
const int BAOHAN        = 1;        // 大圆包含小圆
const int NEIQIE        = 2;        // 内切
const int XIANJIAO      = 3;        // 相交
const int WAIQIE        = 4;        // 外切
const int XIANLI        = 5;        // 相离
///

///
//类型定义区
struct Point {              // 二维点或矢量
    double x, y;
    double angle, dis;
    Point() {}
    Point(double x0, double y0): x(x0), y(y0) {}
};
struct Point3D {            //三维点或矢量
    double x, y, z;
    Point3D() {}
    Point3D(double x0, double y0, double z0): x(x0), y(y0), z(z0) {}
};
struct Line {               // 二维的直线或线段
    Point p1, p2;
    Line() {}
    Line(Point p10, Point p20): p1(p10), p2(p20) {}
};
struct Line3D {             // 三维的直线或线段
    Point3D p1, p2;
    Line3D() {}
    Line3D(Point3D p10, Point3D p20): p1(p10), p2(p20) {}
};
struct Rect {              // 用长宽表示矩形的方法 w, h分别表示宽度和高度
    double w, h;
 Rect() {}
 Rect(double _w,double _h) : w(_w),h(_h) {}
};
struct Rect_2 {             // 表示矩形,左下角坐标是(xl, yl),右上角坐标是(xh, yh)
    double xl, yl, xh, yh;
 Rect_2() {}
 Rect_2(double _xl,double _yl,double _xh,double _yh) : xl(_xl),yl(_yl),xh(_xh),yh(_yh) {}
};
struct Circle {            //圆
 Point c;
 double r;
 Circle() {}
 Circle(Point _c,double _r) :c(_c),r(_r) {}
};
typedef vector<Point> Polygon;      // 二维多边形
typedef vector<Point> Points;       // 二维点集
typedef vector<Point3D> Points3D;   // 三维点集
///

///
//基本函数区
inline double max(double x,double y)
{
    return x > y ? x : y;
}
inline double min(double x, double y)
{
    return x > y ? y : x;
}
inline bool ZERO(double x)              // x == 0
{
    return (fabs(x) < EPS);
}
inline bool ZERO(Point p)               // p == 0
{
    return (ZERO(p.x) && ZERO(p.y));
}
inline bool ZERO(Point3D p)              // p == 0
{
    return (ZERO(p.x) && ZERO(p.y) && ZERO(p.z));
}
inline bool EQ(double x, double y)      // eqaul, x == y
{
    return (fabs(x - y) < EPS);
}
inline bool NEQ(double x, double y)     // not equal, x != y
{
    return (fabs(x - y) >= EPS);
}
inline bool LT(double x, double y)     // less than, x < y
{
    return ( NEQ(x, y) && (x < y) );
}
inline bool GT(double x, double y)     // greater than, x > y
{
    return ( NEQ(x, y) && (x > y) );
}
inline bool LEQ(double x, double y)     // less equal, x <= y
{
    return ( EQ(x, y) || (x < y) );
}
inline bool GEQ(double x, double y)     // greater equal, x >= y
{
    return ( EQ(x, y) || (x > y) );
}
// 注意!!!
// 如果是一个很小的负的浮点数
// 保留有效位数输出的时候会出现-0.000这样的形式,
// 前面多了一个负号
// 这就会导致错误!!!!!!
// 因此在输出浮点数之前,一定要调用次函数进行修正!
inline double FIX(double x)
{
    return (fabs(x) < EPS) ? 0 : x;
}
//

/
//二维矢量运算
bool operator==(Point p1, Point p2)
{
    return ( EQ(p1.x, p2.x) &&  EQ(p1.y, p2.y) );
}
bool operator!=(Point p1, Point p2)
{
    return ( NEQ(p1.x, p2.x) ||  NEQ(p1.y, p2.y) );
}
bool operator<(Point p1, Point p2)
{
    if (NEQ(p1.x, p2.x)) {
        return (p1.x < p2.x);
    } else {
        return (p1.y < p2.y);
    }
}
Point operator+(Point p1, Point p2)
{
    return Point(p1.x + p2.x, p1.y + p2.y);
}
Point operator-(Point p1, Point p2)
{
    return Point(p1.x - p2.x, p1.y - p2.y);
}
double operator*(Point p1, Point p2) // 计算叉乘 p1 × p2
{
    return (p1.x * p2.y - p2.x * p1.y);
}
double operator&(Point p1, Point p2) { // 计算点积 p1·p2
    return (p1.x * p2.x + p1.y * p2.y);
}
double Norm(Point p) // 计算矢量p的模
{
    return sqrt(p.x * p.x + p.y * p.y);
}
// 把矢量p旋转角度angle (弧度表示)
// angle > 0表示逆时针旋转
// angle < 0表示顺时针旋转
Point Rotate(Point p, double angle)
{
    Point result;
    result.x = p.x * cos(angle) - p.y * sin(angle);
    result.y = p.x * sin(angle) + p.y * cos(angle);
    return result;
}
//

//
//三维矢量运算
bool operator==(Point3D p1, Point3D p2)
{
    return ( EQ(p1.x, p2.x) && EQ(p1.y, p2.y) && EQ(p1.z, p2.z) );
}
bool operator<(Point3D p1, Point3D p2)
{
    if (NEQ(p1.x, p2.x)) {
        return (p1.x < p2.x);
    } else if (NEQ(p1.y, p2.y)) {
        return (p1.y < p2.y);
    } else {
        return (p1.z < p2.z);
    }
}
Point3D operator+(Point3D p1, Point3D p2)
{
    return Point3D(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z);
}
Point3D operator-(Point3D p1, Point3D p2)
{
    return Point3D(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z);
}
Point3D operator*(Point3D p1, Point3D p2) // 计算叉乘 p1 x p2
{
    return Point3D(p1.y * p2.z - p1.z * p2.y,
        p1.z * p2.x - p1.x * p2.z,
        p1.x * p2.y - p1.y * p2.x );
}
double operator&(Point3D p1, Point3D p2) { // 计算点积 p1·p2
    return (p1.x * p2.x + p1.y * p2.y + p1.z * p2.z);
}
double Norm(Point3D p) // 计算矢量p的模
{
    return sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
}

//

/
//几何题面积计算
//
// 根据三个顶点坐标计算三角形面积
// 面积的正负按照右手旋规则确定
double Area(Point A, Point B, Point C) //三角形面积
{
    return ((B-A)*(C-A) / 2.0);
}
// 根据三条边长计算三角形面积
double Area(double a, double b, double c) //三角形面积
{
    double s = (a + b + c) / 2.0;
    return sqrt(s * (s - a) * (s - b) * (s - c));
}
double Area(const Circle & C)
{
    return M_PI * C.r * C.r;
}
// 计算多边形面积
// 面积的正负按照右手旋规则确定
double Area(const Polygon& poly) //多边形面积
{
    double res = 0;
    int n = poly.size();
    if (n < 3) return 0;
    for(int i = 0; i < n; i++) {
        res += poly[i].x * poly[(i+1)%n].y;
        res -= poly[i].y * poly[(i+1)%n].x;
    }
    return (res / 2.0);
}
/

/
//点.线段.直线问题
//
double Distance(Point p1, Point p2) //2点间的距离
{
 return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
double Distance(Point3D p1, Point3D p2) //2点间的距离,三维
{
 return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)+(p1.z-p2.z)*(p1.z-p2.z));
}
double Distance(Point p, Line L) // 求二维平面上点到直线的距离
{
    return ( fabs((p - L.p1) * (L.p2 - L.p1)) / Norm(L.p2 - L.p1) );
}
double Distance(Point3D p, Line3D L)// 求三维空间中点到直线的距离
{
    return ( Norm((p - L.p1) * (L.p2 - L.p1)) / Norm(L.p2 - L.p1) );
}
bool OnLine(Point p, Line L) // 判断二维平面上点p是否在直线L上
{
    return ZERO( (p - L.p1) * (L.p2 - L.p1) );
}
bool OnLine(Point3D p, Line3D L) // 判断三维空间中点p是否在直线L上
{
    return ZERO( (p - L.p1) * (L.p2 - L.p1) );
}
int Relation(Point p, Line L) // 计算点p与直线L的相对关系 ,返回ONLINE,LEFT,RIGHT
{
    double res = (L.p2 - L.p1) * (p - L.p1);
    if (EQ(res, 0)) {
        return ONLINE;
    } else if (res > 0) {
        return LEFT;
    } else {
        return RIGHT;
    }
}
bool SameSide(Point p1, Point p2, Line L) // 判断点p1, p2是否在直线L的同侧
{
    double m1 = (p1 - L.p1) * (L.p2 - L.p1);
    double m2 = (p2 - L.p1) * (L.p2 - L.p1);
    return GT(m1 * m2, 0);
}
bool OnLineSeg(Point p, Line L) // 判断二维平面上点p是否在线段l上
{
    return ( ZERO( (L.p1 - p) * (L.p2 - p) ) &&
        LEQ((p.x - L.p1.x)*(p.x - L.p2.x), 0) &&
        LEQ((p.y - L.p1.y)*(p.y - L.p2.y), 0) );
}
bool OnLineSeg(Point3D p, Line3D L) // 判断三维空间中点p是否在线段l上
{
    return ( ZERO((L.p1 - p) * (L.p2 - p)) &&
        EQ( Norm(p - L.p1) + Norm(p - L.p2), Norm(L.p2 - L.p1)) );
}
Point SymPoint(Point p, Line L) // 求二维平面上点p关于直线L的对称点
{
    Point result;
    double a = L.p2.x - L.p1.x;
    double b = L.p2.y - L.p1.y;
    double t = ( (p.x - L.p1.x) * a + (p.y - L.p1.y) * b ) / (a*a + b*b);
    result.x = 2 * L.p1.x + 2 * a * t - p.x;
    result.y = 2 * L.p1.y + 2 * b * t - p.y;
    return result;
}
bool Coplanar(Points3D points) // 判断一个点集中的点是否全部共面
{
    int i;
    Point3D p;

    if (points.size() < 4) return true;
    p = (points[2] - points[0]) * (points[1] - points[0]);
    for (i = 3; i < points.size(); i++) {
        if (! ZERO(p & points[i]) ) return false;
    }
    return true;
}
bool LineIntersect(Line L1, Line L2) // 判断二维的两直线是否相交
{
    return (! ZERO((L1.p1 - L1.p2)*(L2.p1 - L2.p2)) );  // 是否平行
}
bool LineIntersect(Line3D L1, Line3D L2) // 判断三维的两直线是否相交
{
    Point3D p1 = L1.p1 - L1.p2;
    Point3D p2 = L2.p1 - L2.p2;
    Point3D p  = p1 * p2;
    if (ZERO(p)) return false;      // 是否平行
    p = (L2.p1 - L1.p2) * (L1.p1 - L1.p2);
    return ZERO(p & L2.p2);         // 是否共面
}
bool LineSegIntersect(Line L1, Line L2) // 判断二维的两条线段是否相交
{
    return ( GEQ( max(L1.p1.x, L1.p2.x), min(L2.p1.x, L2.p2.x) ) &&
        GEQ( max(L2.p1.x, L2.p2.x), min(L1.p1.x, L1.p2.x) ) &&
        GEQ( max(L1.p1.y, L1.p2.y), min(L2.p1.y, L2.p2.y) ) &&
        GEQ( max(L2.p1.y, L2.p2.y), min(L1.p1.y, L1.p2.y) ) &&
        LEQ( ((L2.p1 - L1.p1) * (L1.p2 - L1.p1)) * ((L2.p2 -  L1.p1) * (L1.p2 - L1.p1)), 0 ) &&
        LEQ( ((L1.p1 - L2.p1) * (L2.p2 - L2.p1)) * ((L1.p2 -  L2.p1) * (L2.p2 - L2.p1)), 0 ) );
}
bool LineSegIntersect(Line3D L1, Line3D L2) // 判断三维的两条线段是否相交
{
    // todo
    return true;
}
// 计算两条二维直线的交点,结果在参数P中返回
// 返回值说明了两条直线的位置关系:  COLINE   -- 共线  PARALLEL -- 平行  CROSS    -- 相交
int CalCrossPoint(Line L1, Line L2, Point& P)
{
    double A1, B1, C1, A2, B2, C2;

    A1 = L1.p2.y - L1.p1.y;
    B1 = L1.p1.x - L1.p2.x;
    C1 = L1.p2.x * L1.p1.y - L1.p1.x * L1.p2.y;

    A2 = L2.p2.y - L2.p1.y;
    B2 = L2.p1.x - L2.p2.x;
    C2 = L2.p2.x * L2.p1.y - L2.p1.x * L2.p2.y;

    if (EQ(A1 * B2, B1 * A2))    {
        if (EQ( (A1 + B1) * C2, (A2 + B2) * C1 )) {
            return COLINE;
        } else {
            return PARALLEL;
        }
    } else {
        P.x = (B2 * C1 - B1 * C2) / (A2 * B1 - A1 * B2);
        P.y = (A1 * C2 - A2 * C1) / (A2 * B1 - A1 * B2);
        return CROSS;
    }
}
// 计算两条三维直线的交点,结果在参数P中返回
// 返回值说明了两条直线的位置关系 COLINE   -- 共线  PARALLEL -- 平行  CROSS    -- 相交  NONCOPLANAR -- 不公面
int CalCrossPoint(Line3D L1, Line3D L2, Point3D& P)
{
    // todo
    return 0;
}
// 计算点P到直线L的最近点
Point NearestPointToLine(Point P, Line L)
{
    Point result;
    double a, b, t;

    a = L.p2.x - L.p1.x;
    b = L.p2.y - L.p1.y;
    t = ( (P.x - L.p1.x) * a + (P.y - L.p1.y) * b ) / (a * a + b * b);

    result.x = L.p1.x + a * t;
    result.y = L.p1.y + b * t;
    return result;
}
// 计算点P到线段L的最近点
Point NearestPointToLineSeg(Point P, Line L)
{
    Point result;
    double a, b, t;

    a = L.p2.x - L.p1.x;
    b = L.p2.y - L.p1.y;
    t = ( (P.x - L.p1.x) * a + (P.y - L.p1.y) * b ) / (a * a + b * b);

    if ( GEQ(t, 0) && LEQ(t, 1) ) {
        result.x = L.p1.x + a * t;
        result.y = L.p1.y + b * t;
    } else {
        if ( Norm(P - L.p1) < Norm(P - L.p2) ) {
            result = L.p1;
        } else {
            result = L.p2;
        }
    }
    return result;
}
// 计算险段L1到线段L2的最短距离
double MinDistance(Line L1, Line L2)
{
    double d1, d2, d3, d4;

    if (LineSegIntersect(L1, L2)) {
        return 0;
    } else {
        d1 = Norm( NearestPointToLineSeg(L1.p1, L2) - L1.p1 );
        d2 = Norm( NearestPointToLineSeg(L1.p2, L2) - L1.p2 );
        d3 = Norm( NearestPointToLineSeg(L2.p1, L1) - L2.p1 );
        d4 = Norm( NearestPointToLineSeg(L2.p2, L1) - L2.p2 );

        return min( min(d1, d2), min(d3, d4) );
    }
}
// 求二维两直线的夹角,
// 返回值是0~Pi之间的弧度
double Inclination(Line L1, Line L2)
{
    Point u = L1.p2 - L1.p1;
    Point v = L2.p2 - L2.p1;
    return acos( (u & v) / (Norm(u)*Norm(v)) );
}
// 求三维两直线的夹角,
// 返回值是0~Pi之间的弧度
double Inclination(Line3D L1, Line3D L2)
{
    Point3D u = L1.p2 - L1.p1;
    Point3D v = L2.p2 - L2.p1;
    return acos( (u & v) / (Norm(u)*Norm(v)) );
}
/

/
//多边行问题:
//
// 判断点p是否在凸多边形poly内
// poly的顶点数目要大于等于3
// 返回值为:
// INSIDE  -- 点在poly内
// BORDER  -- 点在poly边界上
// OUTSIDE -- 点在poly外
int InsideConvex(Point p, const Polygon& poly) // 判断点p是否在凸多边形poly内
{
    Point q(0, 0);
    Line side;
    int i, n = poly.size();

    for (i = 0; i < n; i++) {
        q.x += poly[i].x;
        q.y += poly[i].y;
    }
    q.x /= n;
    q.y /= n;
    for (i = 0; i < n; i++) {
        side.p1 = poly[i];
        side.p2 = poly[(i+1)%n];
        if (OnLineSeg(p, side)) {
            return BORDER;
        } else if (!SameSide(p, q, side)) {
            return OUTSIDE;
        }
    }
    return INSIDE;
}

// 判断多边形poly是否是凸的
bool IsConvex(const Polygon& poly) // 判断多边形poly是否是凸的
{
    int i, n, rel;
    Line side;

    n = poly.size();
    if (n < 3) return false;
    side.p1 = poly[0];
    side.p2 = poly[1];
    rel = Relation(poly[2], side);
    for (i = 1; i < n; i++) {
        side.p1 = poly[i];
        side.p2 = poly[(i+1)%n];
        if (Relation(poly[(i+2)%n], side) != rel) return false;
    }
    return true;
}
// 判断点p是否在简单多边形poly内, 多边形可以是凸的或凹的
// poly的顶点数目要大于等于3
// 返回值为:
// INSIDE  -- 点在poly内
// BORDER  -- 点在poly边界上
// OUTSIDE -- 点在poly外
int InsidePolygon(const Polygon& poly, Point p) // 判断点p是否在简单多边形poly内, 多边形可以是凸的或凹的
{
    int i, n, count;
    Line ray, side;

    n = poly.size();
    count = 0;
    ray.p1    = p;
    ray.p2.y  = p.y;
    ray.p2.x  = - INF;

    for (i = 0; i < n; i++) {
        side.p1 = poly[i];
        side.p2 = poly[(i+1)%n];

        if( OnLineSeg(p, side) ) {
            return BORDER;
        }
        // 如果side平行x轴则不作考虑
        if ( EQ(side.p1.y, side.p2.y) ) {
            continue;
        }
        if (OnLineSeg(side.p1, ray)) {
            if (GT(side.p1.y, side.p2.y)) count++;
        } else if (OnLineSeg(side.p2, ray)) {
            if ( GT(side.p2.y, side.p1.y)) count++;
        } else if (LineSegIntersect(ray, side)) {
            count++;
        }
    }
    return ((count % 2 == 1) ? INSIDE : OUTSIDE);
}
// 判断线段是否在多边形内 (线段的点可能在多边形上)
// 多边形可以是任意简单多边形
bool InsidePolygon(const Polygon& poly, Line L) // 判断线段是否在多边形内 (线段的点可能在多边形上)
{
    bool result;
    int n, i;
    Points points;
    Point p;
    Line side;

    result = ( (InsidePolygon(poly, L.p1) != OUTSIDE) &&
        (InsidePolygon(poly, L.p2) != OUTSIDE) );

    if (!result) return false;

    n = poly.size();
    for (i = 0; i < n; i++) {
        side.p1 = poly[i];
        side.p2 = poly[(i+1)%n];

        if ( OnLineSeg(L.p1, side) ) {
            points.push_back(L.p1);
        } else if ( OnLineSeg(L.p2, side) ) {
            points.push_back(L.p2);
        } else if ( OnLineSeg(side.p1, L) ) {
            points.push_back(side.p1);
        } else if ( OnLineSeg(side.p2, L) ) {
            points.push_back(side.p2);
        } else if( LineSegIntersect(side, L) ) {
            return false;
        }
    }
    // 对交点进行排序
    sort(points.begin(), points.end());

    for (i = 1; i < points.size(); i++) {
        if (points[i-1] != points[i]) {
            p.x = (points[i-1].x + points[i].x) / 2.0;
            p.y = (points[i-1].y + points[i].y) / 2.0;
            if ( InsidePolygon(poly, p) == OUTSIDE ) {
                return false;
            }
        }
    }
    return true;
}
// 寻找凸包 graham 扫描法
// 生成的多边形顶点按逆时针方向排列
bool GrahamComp(const Point& left, const Point& right)
{
    if (EQ(left.angle, right.angle)) {
        return (left.dis < right.dis);
    } else {
        return (left.angle < right.angle);
    }
}

void GrahamScan(Points& points, Polygon& result)
{
    int i, k, n;
    Point p;

    n = points.size();
    result.clear();

    if (n < 3) return;

    // 选取points中y坐标最小的点points[k],
    // 如果这样的点有多个,则取最左边的一个
    k = 0;
    for (i = 1; i < n; i++ ) {
        if (EQ(points[i].y, points[k].y)) {
            if (points[i].x <= points[k].x) k = i;
        } else if (points[i].y < points[k].y) {
            k = i;
        }
    }
    swap(points[0], points[k]);

    // 现在points中y坐标最小的点在points[0]
    // 计算每个点相对于points[0]的极角和距离
    for (i = 1; i < n; i++) {
        points[i].angle = atan2(points[i].y - points[0].y, points[i].x - points[0].x);
        points[i].dis   = Norm(points[i] - points[0]);
    }

    // 对顶点按照相对points[0]的极角从小到大进行排序
    // 对于极角相同的按照距points[0]的距离从小到大排序
    sort(points.begin() + 1, points.end(), GrahamComp);

    // 下面计算凸包
    result.push_back(points[0]);
    for (i = 1; i < n; i++) {
        // 如果有极角相同的点,只取相对于points[0]最远的一个
        if ((i + 1 < n) && EQ(points[i].angle, points[i+1].angle)) continue;
        if (result.size() >= 3) {
            p = result[result.size() - 2];
            while ( GEQ((points[i] - p)*(result.back() - p), 0) )
            {
                result.pop_back();
                p = result[result.size() - 2];
            }
        }
        result.push_back( points[i] );
    }
}
// 用有向直线line切割凸多边形,
// result[LEFT]和result[RIGHT]分别保存被切割后line的左边和右边部分
// result[ONLINE]没有用到,只是用来作为辅助空间
// 返回值是切割多边形的切口的长度,
// 如果返回值是0 则说明未作切割。
// 当未作切割时,如果多边形在该直线的右侧,则result[RIGHT]等于该多边形,否则result[LEFT]等于该多边形
// 注意:被切割的多边形一定要是凸多边形,顶点按照逆时针排列
// 可利用这个函数来求多边形的核,初始的核设为一个很大的矩形,然后依次用多边形的每条边去割
double CutConvex(const Polygon& poly, const Line& line, Polygon result[3])
{
    vector<Point> points;
    Line side;
    Point p;
    int i,n, cur, pre;

    result[LEFT].clear();
    result[RIGHT].clear();
    result[ONLINE].clear();
    n = poly.size();
    if (n == 0) return 0;
    pre = cur = Relation(poly[0], line);

    for (i = 0; i < n; i++) {
        cur = Relation(poly[(i+1)%n], line);
        if (cur == pre) {
            result[cur].push_back(poly[(i+1)%n]);
        } else {
            side.p1 = poly[i];
            side.p2 = poly[(i+1)%n];
            CalCrossPoint(side, line, p);
            points.push_back(p);
            result[pre].push_back(p);
            result[cur].push_back(p);
            result[cur].push_back(poly[(i+1)%n]);
            pre = cur;
        }
    }

    sort(points.begin(), points.end());

    if (points.size() < 2) {
        return 0;
    } else {
        return Norm(points.front() - points.back());
    }
}
// 求多边形的重心,适用于凸的或凹的简单多边形
// 该算法可以一边读入多边性的顶点一边计算重心
Point CenterOfPolygon(const Polygon& poly)
{
    Point p, p0, p1, p2, p3;
    double m, m0;

    p1 = poly[0];
    p2 = poly[1];
    p.x = p.y = m = 0;
    for (int i = 2; i < poly.size(); i++) {
        p3 = poly[i];
        p0.x = (p1.x + p2.x + p3.x) / 3.0;
        p0.y = (p1.y + p2.y + p3.y) / 3.0;
        m0 = p1.x * p2.y + p2.x * p3.y + p3.x * p1.y - p1.y * p2.x - p2.y * p3.x - p3.y * p1.x;
        if (ZERO(m + m0)) {
            m0 += EPS;  // 为了防止除0溢出,对m0做一点点修正
        }
        p.x = (m * p.x + m0 * p0.x) / (m + m0);
        p.y = (m * p.y + m0 * p0.y) / (m + m0);
        m = m + m0;
        p2 = p3;
    }
    return p;
}
// 判断两个矩形是否相交
// 如果相邻不算相交
bool Intersect(Rect_2 r1, Rect_2 r2)
{
    return ( max(r1.xl, r2.xl) < min(r1.xh, r2.xh) &&
             max(r1.yl, r2.yl) < min(r1.yh, r2.yh) );
}
// 判断矩形r2是否可以放置在矩形r1内
// r2可以任意地旋转
//发现原来的给出的方法过不了OJ上的无归之室这题,
//所以用了自己的代码
bool IsContain(Rect r1, Rect r2)      //矩形的w>h
 {
     if(r1.w >r2.w && r1.h > r2.h) return true;
     else
     {
        double r = sqrt(r2.w*r2.w + r2.h*r2.h) / 2.0;
        double alpha = atan2(r2.h,r2.w);
        double sita = asin((r1.h/2.0)/r);
        double x = r * cos(sita - 2*alpha);
        double y = r * sin(sita - 2*alpha);
        if(x < r1.w/2.0 && y < r1.h/2.0 && x > 0 && y > -r1.h/2.0) return true;
        else return false;
     }
}



//圆
Point Center(const Circle & C) //圆心
{
    return C.c;
}

double CommonArea(const Circle & A, const Circle & B) //两个圆的公共面积
{
    double area = 0.0;
    const Circle & M = (A.r > B.r) ? A : B;
    const Circle & N = (A.r > B.r) ? B : A;
    double D = Distance(Center(M), Center(N));
    if ((D < M.r + N.r) && (D > M.r - N.r))
    {
        double cosM = (M.r * M.r + D * D - N.r * N.r) / (2.0 * M.r * D);
        double cosN = (N.r * N.r + D * D - M.r * M.r) / (2.0 * N.r * D);
        double alpha = 2.0 * acos(cosM);
        double beta  = 2.0 * acos(cosN);
        double TM = 0.5 * M.r * M.r * sin(alpha);
        double TN = 0.5 * N.r * N.r * sin(beta);
        double FM = (alpha / 360.0) * Area(M);
        double FN = (beta / 360.0) * Area(N);
        area = FM + FN - TM - TN;
    }
    else if (D <= M.r - N.r)
    {
        area = Area(N);
    }
    return area;
}

bool IsInCircle(const Circle & C, const Rect_2 & rect)//判断圆是否在矩形内(不允许相切)
{
    return (GT(C.c.x - C.r, rect.xl)
  &&  LT(C.c.x + C.r, rect.xh)
  &&  GT(C.c.y - C.r, rect.yl)
  &&  LT(C.c.y + C.r, rect.yh));
}

//判断2圆的位置关系
//返回:
//BAOHAN   = 1;        // 大圆包含小圆
//NEIQIE   = 2;        // 内切
//XIANJIAO = 3;        // 相交
//WAIQIE   = 4;        // 外切
//XIANLI   = 5;        // 相离
int CirCir(const Circle &c1, const Circle &c2)//判断2圆的位置关系
{
 double dis = Distance(c1.c,c2.c);
 if(LT(dis,fabs(c1.r-c2.r))) return BAOHAN;
 if(EQ(dis,fabs(c1.r-c2.r))) return NEIQIE;
 if(LT(dis,c1.r+c2.r) && GT(dis,fabs(c1.r-c2.r))) return XIANJIAO;
 if(EQ(dis,c1.r+c2.r)) return WAIQIE;
 return XIANLI;
}


int main(){

    Point a , b , c , d , aa , bb , cc , dd , p1 , p2 , p3 , p4;
    Line l1 , l2 , l3 , l4;

    double t , t1 , t2 , t3 , t4 , t5;
    double ans1 , ans2 , ans3 , ans4 , ans5 , ans6;
    int ans7;

    scanf("%d" , &n);

        for(int z = 1 ; z <= n ; z ++){

            ans5 = 0;
            ans6 = 0;

            scanf("%*d%lf%lf%lf%lf%lf" , &t1 , &t2 , &t3 , &t4 , &t5);
            a.x = 0;
            a.y = 0;
            b.x = t1;
            b.y = 0;
            c.x = t2;
            c.y = t3;
            d.x = t4;
            d.y = t5;

            aa.x = (b.x + c.x) / 2;
            aa.y = (b.y + c.y) / 2;
            bb.x = (d.x + c.x) / 2;
            bb.y = (d.y + c.y) / 2;
            cc.x = (a.x + d.x) / 2;
            cc.y = (a.y + d.y) / 2;
            dd.x = (a.x + b.x) / 2;
            dd.y = (a.y + b.y) / 2;

            l1.p1 = a;
            l1.p2 = aa;
            l2.p1 = b;
            l2.p2 = bb;
            l3.p1 = c;
            l3.p2 = cc;
            l4.p1 = d;
            l4.p2 = dd;

            CalCrossPoint(l1 , l2 , p1);
            //printf("p1.x = %lf p1.y = %lf\n" , p1.x , p1.y);
            ans1 = Area(a , b , p1);

            CalCrossPoint(l2 , l3 , p2);
            ans2 = Area(b , c , p2);

            CalCrossPoint(l3 , l4 , p3);
            ans3 = Area(c , d , p3);

            CalCrossPoint(l4 , l1 , p4);
            ans4 = Area(d , a , p4);

            ans5 += Area(p1 , p2 , p3);
            ans5 += Area(p3 , p4 , p1);

            ans6 += Distance(p1 , p2);
            ans6 += Distance(p2 , p3);
            ans6 += Distance(p3 , p4);
            ans6 += Distance(p4 , p1);
            ans6 *= 16.5;
            ans7 = ceil(ans6);

            printf("%d %.3lf %.3lf %.3lf %.3lf %.3lf %d\n" , z , ans1 / 160 , ans2 / 160 , ans3 / 160 , ans4 / 160 , ans5 / 160 , ans7);


        }



    return 0;
}





/*
3
1 200 250 150 -50 200
2 200 200 100 0 100
3 201.5 157.3 115.71 -44.2 115.71
*/


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值