http://acm.pku.edu.cn/JudgeOnline/problem?id=1279
这个问题是所谓多边形的核,在一个多边形(不一定是凸的),要求找到一个区域,使得在这个区域可见多边形的所有边界。#include <cmath>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
typedef double TYPE;
#define MaxPoint 1550
#define Epsilon 1e-10 /*验证*///精度的范围 ,根据不同的情况调整精度值
#define Abs(x) (((x)>0)?(x):(-(x))) /*验证*/
//空间中的点,可以用来作为二维点来用
struct POINT {/*验证*/
TYPE x; TYPE y; TYPE z;
POINT() : x(0), y(0), z(0) {};
POINT(TYPE _x_, TYPE _y_, TYPE _z_ = 0)
: x(_x_), y(_y_), z(_z_) {};
//要用 G++ 提交 ,可以不用这个
POINT operator =(const POINT &A){
x = A.x;
y = A.y;
z = A.z;
}
};
// 多边形 ,逆时针或顺时针给出x,y
struct POLY {/*验证*/
//n个点
int n;
//x,y为点的指针,首尾必须重合
TYPE * x;
TYPE * y;
POLY() : n(0), x(NULL), y(NULL) {};
POLY(int _n_, const TYPE * _x_, const TYPE * _y_) {
n = _n_;
x = new TYPE[n + 1];
memcpy(x, _x_, n*sizeof(TYPE));
x[n] = _x_[0];
y = new TYPE[n + 1];
memcpy(y, _y_, n*sizeof(TYPE));
y[n] = _y_[0];
}
};
//判断 x 是正数还是负数
inline int Sign(TYPE x){/*验证*/
return x<-Epsilon?-1:x>Epsilon;
}
void Interect(POINT x,POINT y,TYPE a,TYPE b,TYPE c,int &s,POINT q[]){
TYPE u=fabs(a*x.x+b*x.y+c);
TYPE v=fabs(a*y.x+b*y.y+c);
q[++s].x=(x.x*v+y.x*u)/(u+v);
q[s].y=(x.y*v+y.y*u)/(u+v);
}
//利用半平面切割
void Cut(TYPE a,TYPE b,TYPE c,int &KarnalPoint,POINT p[])
{
int s=0;
int i;
POINT q[MaxPoint];
for(i=1; i<=KarnalPoint; i++){//遍历所有顶点是否能观察到该边
if(Sign(a* p[i].x+ b*p[i].y+ c)>= 0){//因为线段是顺时针给出的,如果是逆时针就是<=0
q[++s]= p[i]; //若是则存储
}
else{
if(Sign(a* p[i-1].x+ b* p[i-1].y+ c)> 0)//逆时针就是<0
Interect(p[i-1], p[i], a, b, c, s, q);
if(Sign(a* p[i+1].x+ b* p[i+1].y+ c)> 0)//逆时针就是<0
Interect(p[i+1], p[i], a, b, c, s, q);
}
}
//最后的p数组存放半平面的点集合
for(i=1;i<=s;i++)
p[i]=q[i];
p[s+1]=p[1],p[0]=p[s];
KarnalPoint=s;
}
POLY PolygonKernal(int n, POINT point[])
{
int KarnalPoint= n;
POINT p[MaxPoint];//p 的大小和 tr 的大小一样
for(int i= 0; i< n; i++){
p[i+1]= point[i]; //初始化边界
}
point[n]= point[0];
p[n+1]= p[1];
p[0] = p[n];
TYPE a,b,c;
for(int i=0;i<n;i++){
a=point[i+1].y- point[i].y ; //计算出相邻两点所在直线ax+by+c=0
b=point[i].x - point[i+1].x;
c=point[i+1].x* point[i].y- point[i].x* point[i+1].y;
Cut(a, b, c, KarnalPoint, p);
}
TYPE X[MaxPoint],Y[MaxPoint];
for(int i= 0; i< KarnalPoint; i++){
X[i]= p[i].x;
Y[i]= p[i].y;
}
POLY poly(KarnalPoint, X, Y);
return poly;
}
//求多边形面积 拍好序的点 (返回的有可能是负数,Abs 一下)
TYPE Area(const POLY & poly) { /*验证*/
if ( poly.n < 3)
return TYPE(0);
double s = poly.y[0] * (poly.x[poly.n - 1] - poly.x[1]);
for (int i = 1; i < poly.n; i++) {
s += poly.y[i] * (poly.x[i - 1] - poly.x[(i + 1) % poly.n]);
}
return s/2;
}
int main(){
int n,t;
POINT point[MaxPoint];
cin>>t;
while(t--)
{
cin>>n;
for(int i=0;i<n;i++){
scanf("%lf%lf",&point[i].x,&point[i].y);
}
POLY poly= PolygonKernal(n, point);
TYPE s= Area(poly);
//之前用自定义的 Abs 宏定义,出现错误,改成下面的就 AC 了
if(s< 0) printf("%.2f\n",-s);
else printf("%.2f\n", s);
}
return 0;
}