算法题 Area

Area from ZOJ(浙大OJ) Problem Set - 1010,链接http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1010

题目如下:

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

题目简述:

给你一些点,将这些点依次连接,判断是否交叉,若没有交叉则计算该图形的面积。

思路

借鉴自https://www.cnblogs.com/TangMoon/archive/2017/09/29/7611115.htmlhttps://blog.csdn.net/yf224/article/details/73471739

  1. 用跨立实现判断是否相交
  2. 向量的叉乘求面积

跨立实现判断是否相交

int is_cross(double vertex[SIZE][2], int i1, int i2, int j1, int j2)
{
    double a, b, c, d;
    a = CAL(vertex[i1][X] - vertex[j1][X], 
            vertex[i1][Y] - vertex[j1][Y], 
            vertex[j2][X] - vertex[j1][X], 
            vertex[j2][Y] - vertex[j1][Y]);
    
    b = CAL(vertex[j2][X] - vertex[j1][X], 
            vertex[j2][Y] - vertex[j1][Y], 
            vertex[i2][X] - vertex[j1][X], 
            vertex[i2][Y] - vertex[j1][Y]);

    c = CAL(vertex[j1][X] - vertex[i1][X], 
            vertex[j1][Y] - vertex[i1][Y], 
            vertex[i2][X] - vertex[i1][X], 
            vertex[i2][Y] - vertex[i1][Y]);

    d = CAL(vertex[i2][X] - vertex[i1][X], 
            vertex[i2][Y] - vertex[i1][Y], 
            vertex[j2][X] - vertex[i1][X], 
            vertex[j2][Y] - vertex[i1][Y]);
    
    if (a * b >= 0 && c * d >= 0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

该函数基于下面两个公式:
[(P1x-Q1x)*(Q2y-Q1y)-(P1y-Q1y)*( Q2x-Q1x)] * [(Q2x-Q1x)*(P2y-Q1y)-(Q2y-Q1y)*(P2x-Q1x)] > 0
[(Q1x-P1x)*(P1y-P2y)-(Q1y-P1y)*( P2x-P1x)] * [(P2x-P1x)*(Q2y-P1y)-(P2y-P1y)*(Q2x-P1x)] > 0

叉乘求面积

double area(double vertex[SIZE][2], int n)
{
    double area = 0;
    int i;
    for (i = 2; i < n; i++)
    {
        area += CAL(vertex[i - 1][X] - vertex[0][X], 
                    vertex[i - 1][Y] - vertex[0][Y], 
                    vertex[i][X] - vertex[0][X], 
                    vertex[i][Y] - vertex[0][Y]);
    }
    return fabs(area) / 2.0;
}

具体原理参考该博客-【ACM】向量的叉乘(求面积)(https://blog.csdn.net/TwT520Ly/article/details/54426837)

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define SIZE 1024
#define X 0
#define Y 1

#define CAL(a, b, c, d) ((a) * (d) - (c) * (b))

double area(double vertex[SIZE][2], int n)
{
    double area = 0;
    int i;
    for (i = 2; i < n; i++)
    {
        area += CAL(vertex[i - 1][X] - vertex[0][X], 
                    vertex[i - 1][Y] - vertex[0][Y], 
                    vertex[i][X] - vertex[0][X], 
                    vertex[i][Y] - vertex[0][Y]);
    }
    return fabs(area) / 2.0;
}

int is_cross(double vertex[SIZE][2], int i1, int i2, int j1, int j2)
{
    double a, b, c, d;
    a = CAL(vertex[i1][X] - vertex[j1][X], 
            vertex[i1][Y] - vertex[j1][Y], 
            vertex[j2][X] - vertex[j1][X], 
            vertex[j2][Y] - vertex[j1][Y]);
    
    b = CAL(vertex[j2][X] - vertex[j1][X], 
            vertex[j2][Y] - vertex[j1][Y], 
            vertex[i2][X] - vertex[j1][X], 
            vertex[i2][Y] - vertex[j1][Y]);

    c = CAL(vertex[j1][X] - vertex[i1][X], 
            vertex[j1][Y] - vertex[i1][Y], 
            vertex[i2][X] - vertex[i1][X], 
            vertex[i2][Y] - vertex[i1][Y]);

    d = CAL(vertex[i2][X] - vertex[i1][X], 
            vertex[i2][Y] - vertex[i1][Y], 
            vertex[j2][X] - vertex[i1][X], 
            vertex[j2][Y] - vertex[i1][Y]);
    
    if (a * b >= 0 && c * d >= 0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

int judge(double vertex[SIZE][2], int n)
{
    int i, j;
    for (i = 3; i < n; i++)
    { //不判断最后一条,因为最后一个点是从第n个点到第0个点
        for (j = 1; j < i - 1; j++)
        {
            if (is_cross(vertex, i - 1, i, j - 1, j))
            {
                return 0;
            }
        }
    }
    for (i = 2; i < n - 1; i++)
    { //判断最后一条
        if (is_cross(vertex, i - 1, i, n - 1, 0))
        {
            return 0;
        }
    }
    return 1;
}

int main()
{
    int i, n, flag;
    double vertex[SIZE][2];
    flag = 0;
    while (scanf("%d", &n) != EOF && n != 0)
    {
        for (i = 0; i < n; i++)
        {
            scanf("%lf %lf", &vertex[i][X], &vertex[i][Y]);
        }
        if (flag != 0)
        {
            puts("");
        }
        flag++;
        printf("Figure %d: ", flag);
        if (n < 3 || !judge(vertex, n))
        { //少于3个点就围不成一个多边形
            puts("Impossible");
            continue;
        }
        if (judge(vertex, n))
        {
            printf("%.2lf\n", area(vertex, n));
        }
    }
    return 0;
}

总结

对于算法来说,数学也至关重要。