【Algorithm】 多边形+凸包+面积

来源:互联网 发布:怎样撤回淘宝手机充值 编辑:程序博客网 时间:2024/05/18 15:08

例题:

In order for a living creature to survive, it needs an appropriate size of territory of its own.
Hence, it is natural that living organisms fight over territory.
In the figure above places where a rabbit left its scent to mark its areas were shown with red dots,
and the inside of a polygon drawn with a black line which includes all dots is called a territory.
If there is an intruder, in many cases a fierce fight takes places.


When multiple dots with which a rabbit marked its areas are given, what is the area of the rabbit’s territory that includes all dots?


Time limit : 1 sec (Java : 2 sec)


[Input]
There can be more than one test case in the input file. The first line has T, the number of test cases.
Then the totally T test cases are provided in the following lines (T ≤ 10 )


In each test case,
In the first line, the number of dots N (3 ≤ N ≤ 100) is given.
From the second line, two integers x and y (-10000 ≤ x, y ≤ 10000) are given, separated by blanks in N lines.
X and y are coordinates of i-th dot, and the coordinates of each dot are different from each another.


[Output]
Output the area of the rabbit’s territory after rounding to hundredths place in the first line.


[I/O example]

Input
2
7
10 30
30 10
20 0
30 30
50 10
40 50
60 30
20
8 -2
39 38
-22 -5
0 64
70 -8
-7 -30
40 -21
68 12
30 46
58 45
-24 40
8 1
16 66
41 58
37 25
20 -22
43 38
-12 14
29 40
-9 -4


Output
1500.00
6863.50



知识点运用

1)凸包算法

http://www.cnblogs.com/jbelial/archive/2011/08/05/2128625.html

2)矢量叉积法

http://blog.csdn.net/wrq147/article/details/5379092

3)多边形面积公式

http://blog.csdn.net/hemmingway/article/details/7814494


题解步骤:

1)先找出最左边的点,作为起始点

2)用矢量叉积法,将其余点按照逆时针顺序排序

3)将凸点存入新的数组,用面积公式计算多边形面积


示例代码(Implement  by Chunyin):

#include <stdio.h>

typedef struct node { // 点结构体
    int x;
 int y;
}PointX;


int N;//(3 ≤ N ≤ 100
PointX data[105];
double Answer;
PointX data_TuBao[105];
int len_TuBa0;


// 点的叉乘: AB * AC 若AB*AC>0, AB 在AC的顺时针方向。
int cross(const PointX A, const PointX B, const PointX C) {
    return (B.x - A.x) * (C.y - A.y) - (B.y - A.y) * (C.x - A.x);
}

//点A*B的距离的平方
double distance(const PointX A, const PointX B)
{
 return (A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y);
}

/*
 * 计算多边形面积
 * 参数:n个顶点, 多边形顶点坐标集合
 */
double polygon_area(const int n, PointX p[])
{
    double area = 0.0;
    int i;
    PointX temp=p[1];
    for (i = 2; i < n; ++i){
        area += cross(temp, p[i], p[i+1]);
    }
    area = area/2.0;      
    return area > 0 ? area : -area;   
}

int main(void)
{
 int tc, T, i,j; 
 // The freopen function below opens input.txt file in read only mode, and afterward,
 // the program will read from input.txt file instead of standard(keyboard) in

 setbuf(stdout, NULL);

 scanf("%d",&T);
  for(tc = 0; tc < T; tc++)
    {
  scanf("%d",&N);
       for(i=1;i<=N;i++) {
     scanf("%d%d",&data[i].x,&data[i].y);
       }

    Answer = 0.0;

    //计算左下角数并逆时针排序
    int temp=1;
    for(i=2;i<=N;i++)
     if(data[temp].y-data[i].y>0 || (data[temp].y-data[i].y==0 && data[temp].x>data[i].x))
    temp=i;
  
  PointX tempPointX=data[temp];
  data[temp]=data[1];
  data[1]=tempPointX;

  //排序。
  for(i=2;i<N;i++)
  {
   temp=i;
   for(j=temp+1; j<=N;j++)
   {
    if((cross(data[1],data[j],data[temp])>0 )||  (cross(data[1],data[j],data[temp])==0 && distance(data[1],data[j])>distance(data[1],data[temp])))
    {
     temp=j;
    }
   }
   tempPointX=data[temp];
   data[temp]=data[i];
   data[i]=tempPointX;
  }


  //凸包计算
  data_TuBao[1]=data[1];
  data_TuBao[2]=data[2];
  data_TuBao[3]=data[3];
  len_TuBa0=3;
  
  for(i=4;i<N+1;i++)
  {
   while(cross(data_TuBao[len_TuBa0-1],data_TuBao[len_TuBa0],data[i])<=0)
    len_TuBa0--;
   
    data_TuBao[++len_TuBa0]=data[i];
    
  }
  Answer=polygon_area(len_TuBa0,data_TuBao);

    printf("%.2f\n",Answer);

  }

 return 0;
}


0 0
原创粉丝点击