Area 快速排斥+跨立实验+叉积求面积 合工大程序设计与艺术实验三

Area Time Limit: 2 Seconds Memory Limit: 65536 KB Special
Judge Jerry, a middle school student, addicts himself to mathematical
research. Maybe the problems he has thought are really too easy to an
expert. But as an amateur, especially as a 15-year-old boy, he had
done very well. He is so rolling in thinking the mathematical problem
that he is easily to try to solve every problem he met in a
mathematical way. One day, he found a piece of paper on the desk. His
younger sister, Mary, a four-year-old girl, had drawn some lines. But
those lines formed a special kind of concave polygon by accident as
Fig. 1 shows.

Fig. 1 The lines his sister had drawn

“Great!” he thought, “The polygon seems so regular. I had just learned
how to calculate the area of triangle, rectangle and circle. I’m sure
I can find out how to calculate the area of this figure.” And so he
did. First of all, he marked the vertexes in the polygon with their
coordinates as Fig. 2 shows. And then he found the result–0.75
effortless.

Fig.2 The polygon with the coordinates of vertexes

Of course, he was not satisfied with the solution of such an easy
problem. “Mmm, if there’s a random polygon on the paper, then how can
I calculate the area?” he asked himself. Till then, he hadn’t found
out the general rules on calculating the area of a random polygon. He
clearly knew that the answer to this question is out of his
competence. So he asked you, an erudite expert, to offer him help. The
kind behavior would be highly appreciated by him.

Input

The input data consists of several figures. The first line of the
input for each figure contains a single integer n, the number of
vertexes in the figure. (0 <= n <= 1000).

In the following n lines, each contain a pair of real numbers, which
describes the coordinates of the vertexes, (xi, yi). The figure in
each test case starts from the first vertex to the second one, then
from the second to the third, and so on. At last, it closes from the
nth vertex to the first one.

The input ends with an empty figure (n = 0). And this figure not be
processed.

Output

As shown below, the output of each figure should contain the figure
number and a colon followed by the area of the figure or the string
“Impossible”.

If the figure is a polygon, compute its area (accurate to two
fractional digits). According to the input vertexes, if they cannot
form a polygon (that is, one line intersects with another which
shouldn’t be adjoined with it, for example, in a figure with four
lines, the first line intersects with the third one), just display
“Impossible”, indicating the figure can’t be a polygon. If the amount
of the vertexes is not enough to form a closed polygon, the output
message should be “Impossible” either.

Print a blank line between each test cases.

Sample Input

5 0 0 0 1
0.5 0.5 1 1 1 0 4 0 0 0 1 1 0 1 1 0

Output for the Sample Input

Figure 1: 0.75

Figure 2: Impossible

算法思想:
利用快速排斥和跨立实验验证两直线是否相交,面积用叉积计算即可.
验证相交时需要注意最后一个点的特殊性.

快速排斥实验简介:在这里插入图片描述

跨立思想简介:
在这里插入图片描述

程序源码:

#include <iostream>
#include <vector>
#include <utility>
#include <math.h>
using namespace std;

struct POINT//构造一个点的结构
{
    
    
    double x, y;

    POINT() {
    
    }
    POINT(double _x, double _y)//构造函数
    {
    
    
        x = _x;
        y = _y;
    }
    POINT operator - (POINT n) //对减号重新定义  为了方便计算向量
    {
    
    
        POINT point;
        point.x = x - n.x;
        point.y = y - n.y;
        return point;
    }
};

double crossProduct (POINT p, POINT p1, POINT p2)
{
    
    //用来求叉积  p.p1叉乘p.p2
    POINT a = p1 - p;
    POINT b = p2 - p;//两个向量
    return a.x * b.y - b.x * a.y;
}

bool isIntersect(POINT a1, POINT a2, POINT b1, POINT b2)//该函数用来判断线段a1.a2  与 线段 b1.b2是否相交
{
    
    
    //这个if是快速排斥实验的条件
    if(min(a1.x, a2.x) <= max(b1.x, b2.x) && min(b1.x, b2.x) <= max(a1.x, a2.x) &&
       min(a1.y, a2.y) <= max(b1.y, b2.y) && min(b1.y, b2.y) <= max(a1.y, a2.y) )
    {
    
    
        //在满足快速排斥实验的基础上我们再进行跨立实验
        double c1 = crossProduct(a1, b1, a2);//a1b 叉乘 a1a2
        double c2 = crossProduct(a1, b2, a2);//a1b2 叉乘 a1a2
        double c3 = crossProduct(b1, a1, b2);//b1a1 叉乘 b1b2
        double c4 = crossProduct(b1, a2, b2);//b1a2 叉乘 b1b2
        if(c1 * c2 <= 0 && c3 * c4 <= 0) return true;  //两条直线相互跨立则返回true
    }
    return false ;
}

bool isPolygon(vector<POINT> points)//判断是否是合格的多边形
{
    
    
    for(int i = 2; i < points.size() - 1; i++)
    {
    
    //从第2条边开始判断第i条边与从第0条边开始不相邻的边是否相交  (说明:我们的边和点都是从0开始计数)
        for(int j = 0; j < i - 1; j++)
        {
    
    
            if(isIntersect(points[i], points[i + 1], points[j], points[j + 1]))
                return false;
        }
    }

    //因为最后一条边的终点与起点相连 所以单独来一个for循环讨论
    for(int j = 1; j < points.size() - 2; j++)
    {
    
    
        if(isIntersect(points[points.size()- 1], points[0], points[j], points[j + 1]))
                return false;
    }

    return true;
}

double getArea(vector<POINT> points)
{
    
    //叉积求面积
    POINT p0 = points.front();
    double S = 0;
    for(int i = 1; i < points.size() - 1; i++){
    
    
        S += crossProduct(p0, points[i], points[i + 1]);
    }
    return fabs(S / 2);
}

int main()
{
    
    
    vector<POINT> points;
    int n = 0;
    int i = 1;
    double x, y;
    while(cin >> n && n)
    {
    
    
        if(n < 3) cout << "Figure " << i << ": " << "Impossible !" << endl; // 点的个数小于3 则直接pass
        else{
    
    
            for(int j = 0; j < n; j++){
    
    
                cin >> x >> y;
                points.push_back(POINT(x, y));//把点压入容器中
            }

            if(isPolygon(points))//如果可以构成多边形则计算面积
            {
    
    
                double S = getArea(points);
                cout << "Area";
                cout << "Figure " << i << ": " << S << endl;
            }
            else
            {
    
    
                cout << "Figure " << i << ": " << "Impossible !" << endl;
            }
        }
        points.clear();//每回计算完毕清空容器进行下一次计算
        i++;
    }
    return 0;
}


测试数据:
/*
测试数据:

5
0.01 0.01
0.01 1.01
0.51 0.51
1.01 1.01
1.01 0.01
4
0.01 0.01
0.01 1.01
1.01 0.01
1.01 1.01
4
0.01 0.01
1.01 0.01
2.01 1.01
2.01 0.01
5
0.01 0.01
2.01 0.01
2.01 1.01
1.01 0.01
0.01 1.01
4
0.01 0.01
1.01 -1.01
2.01 1.01
2.01 0.01
6
0.01 1.01
1.01 0.01
4.01 2.01
3.01 3.01
4.01 3.01
2.01 4.01
6
0.01 0.01
1.01 1.01
2.01 0.01
2.01 2.01
3.01 3.01
0.01 3.01
3
0.01 0.01
1.01 1.01
1.01 0.01

Figure 1: 0.75

Figure 2: Impossible

Figure 3: Impossible

Figure 4: Impossible

Figure 5: Impossible

Figure 6: 8.00

Figure 7: 5.50

Figure 8: 0.50
*/

运行截图:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_42650433/article/details/106394981