暴力: 貌似只适用于求两个多边形的相交面积,但是可以求任意多边形(凹凸)。
1.设两个多边形点集为P1,P2,相交区域点集为P。
2.遍历P1的点是否在P2内,若在内部,则加入点集P;对P2也做相同操作。
3.遍历P1的边和P2的边,求出两个多边形的交点,将交点加入P。
4.求点集P的面积。
半平面交: 这个只适用凸包,但是可以求任意个凸包最终相交的面积。
1.把每个凸包的点按照逆时针排序。(当然也看自己的算法是要什么顺序,大多数需要逆时针)
2.将每个凸包的边放入边集L。
3.求边集L的半平面交,再求半平面交的面积。
求一次半平面交:O(nlogn),n为边数
题目:ECNU 1624
暴力就不写了,写个半平面交的:
#include<bits/stdc++.h>
#define ll long long
#define lf double
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define Rep(i,l,r) for(int i=(l);i<=(r);i++)
using namespace std;
struct Point {double x, y;};
typedef Point vector_t;
typedef Point point_t;
struct Line {Point x;vector_t v;};
double Cross(const vector_t& x, const vector_t& y) {return x.x * y.y - x.y * y.x;} //叉积
vector_t operator*(const vector_t& v, double t) {return (vector_t){v.x * t, v.y * t};}
vector_t operator+(const vector_t& a, const vector_t& b) {return (vector_t){a.x + b.x, a.y + b.y};}
Point operator-(const Point& a, const Point& b) {return (Point){a.x - b.x, a.y - b.y};}
point_t GetLineIntersection(Line a,Line b){//求两直线交点
Point P=a.x;vector_t v=a.v;
Point Q=b.x;vector_t w=b.v;
vector_t u = P-Q;
double t = Cross(w, u)/Cross(v, w);
return P+v*t;//由直线的点向式而来
}
double eps=1e-6;
Point tmpP[500];
Line tmpL[500];
bool cmp1(const Line& a,const Line& b) { return atan2(a.v.y,a.v.x)<atan2(b.v.y,b.v.x); }//极角排序
int dcmp(double x){ if(fabs(x)<eps)return 0; if(x>0)return 1; return -1;}
bool Onleft(Line l,Point p) { return dcmp(Cross(l.v,(p-l.x))) > 0; }//ToLeftTest
int HalfPol(Line *l,int n,vector<Point> &p)
{
sort(l,l+n,cmp1);//把边按极角排序
int hd = 0,tl = 0;
tmpL[0] = l[0];
for(int i=0;i<n;i++)
{
while(hd<tl&&!Onleft(l[i],tmpP[tl-1]))tl--;
while(hd<tl&&!Onleft(l[i],tmpP[hd]))hd++;
tmpL[++tl] = l[i];
if(!dcmp(Cross(tmpL[tl].v,tmpL[tl-1].v)))
{
tl--;
if(Onleft(tmpL[tl],l[i].x))tmpL[tl]=l[i];
}
if(hd<tl)tmpP[tl-1] = GetLineIntersection(tmpL[tl-1],tmpL[tl]);//求两直线交点
}
while(hd<tl&&!Onleft(tmpL[hd],tmpP[tl-1]))tl--;
if(tl-hd<=1)return 0;
tmpP[tl] = GetLineIntersection(tmpL[hd],tmpL[tl]);
for(int i=hd;i<=tl;i++)p.push_back(tmpP[i]);
return tl-hd+1;
}
double PolygonArea(point_t* p, int n){//p为端点集合,n为端点个数
double s = 0;
for(int i = 1; i < n-1; i++)
s += Cross(p[i]-p[0], p[i+1]-p[0]);
return s/2;
}
int n,m;
Point P[205];
Line L[205];
vector<Point>s;
Point ss[205];
int main()
{
cin>>n;
int cntl=0;
Rep(i,0,n-1){
double x,y;cin>>x>>y;
P[i].x=x;P[i].y=y;
}
for(int i=0;i<n;i++){
L[cntl++].v=P[i]-P[(i+1)%n];
L[cntl].x=P[(i+1)%n];
}
cin>>m;
Rep(i,0,m-1){
double x,y;cin>>x>>y;
P[i].x=x;P[i].y=y;
}
for(int i=0;i<m;i++){//题目按顺时针给的,就反着来
L[cntl].v=P[i]-P[(i+1)%m];
L[cntl].x=P[(i+1)%m];
cntl++;
}
int sn=HalfPol(L,cntl,s);
std::copy(s.begin(),s.end(),ss);//把s的数据copy到ss
double S=PolygonArea(ss,sn);
printf("%.2lf\n",S);
return 0;
}