[HNOI2003 多边形]

[关键字]:计算几何 数学

[题目大意]:找出给定的简单多边形的核的面积。

//====================================================================================

[分析]:一个裸的求半平面交的题目,可以用来练习模板。O(n2)算法:每次枚举一条边去切割当前剩余的多边形,直到所有边都枚举过一遍,剩余的多边形面积可以用三角剖分,然后利用叉积求出每个三角形的有向面积累加。

[代码]:

View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

const double ZERO=1e-8;

struct Point
{
double x,y;
};
struct node
{
int n;
Point p[2000];
}a,b;
int n;

double det(Point p0,Point p1,Point p2)
{
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}

Point Find(double a1,double b1,double c1,double a2,double b2,double c2)
{
Point p;
p.y=(c2*a1-c1*a2)/(a1*b2-a2*b1);
if (fabs(a2)<ZERO)
p.x=(p.y*b1-c1)/a1;
else
p.x=(p.y*b2-c2)/a2;
return p;
}

void Getline(Point p1,Point p2,double &a,double &b,double &c)
{
a=p2.y-p1.y;
b=p2.x-p1.x;
c=p1.y*(p2.x-p1.x)-p1.x*(p2.y-p1.y);
}

bool Same(Point p1,Point p2)
{
return fabs(p1.x-p2.x)<ZERO && fabs(p1.y-p2.y)<ZERO;
}

node Cut(Point A,Point B)
{
node c;
double r1,r2,a1,b1,c1,a2,b2,c2;
c.n=0;
for (int i=0;i<b.n;++i)
{
r1=det(A,B,b.p[i]);
r2=det(A,B,b.p[i+1]);
if (r1<ZERO && r2<ZERO)
{
c.p[c.n++]=b.p[i];
c.p[c.n++]=b.p[i+1];
}
else if (r1>ZERO && r2>ZERO)
continue;
else
{
Getline(A,B,a1,b1,c1);
Getline(b.p[i],b.p[i+1],a2,b2,c2);
Point cross=Find(a1,b1,c1,a2,b2,c2);
if (r1<ZERO)
{
c.p[c.n++]=b.p[i];
c.p[c.n++]=cross;
}
else
{
c.p[c.n++]=cross;
c.p[c.n++]=b.p[i+1];
}
}
}
if (c.n==0) return c;
int j=1;
for (int i=1;i<c.n;++i)
if (!Same(c.p[i],c.p[i-1]))
c.p[j++]=c.p[i];
c.n=j;
if (c.n!=1 && Same(c.p[c.n-1],c.p[0]))
c.n--;
c.p[c.n]=c.p[0];
return c;
}

int main()
{
int test;
scanf("%d",&test);
while (test--)
{
scanf("%d",&n);
for (int i=0;i<n;++i)
scanf("%lf%lf",&a.p[i].x,&a.p[i].y);
a.p[n]=a.p[0];
a.n=n;
b=a;
for (int i=0;i<a.n;++i)
b=Cut(a.p[i],a.p[i+1]);
double area=0.0;
for (int i=1;i<b.n-1;++i)
area+=det(b.p[0],b.p[i],b.p[i+1]);
printf("%.2lf\n",fabs(area)/2.0);
}
return 0;
}



你可能感兴趣的:(2003)