裸的半平面交。
这个题没说输入是顺时针还是逆时针,可以用面积判断,多边形面积如果是顺时针,面积为负,改变下方向即可。
粘两个模板。
code 1:
//书27页
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
#define MAXN 1510
const double EPS=1e-12;
//半平面为向量表示,平面维宇向量左侧
struct point{
double x,y; } convex[MAXN];
struct line{
point a,b;
double ang; //角度(弧度)
}l[MAXN],st[MAXN];
int n,ccnt;
double operator *(const point &x,const point &y)//向量叉乘3
{ return x.x*y.y-x.y*y.x; }
point operator -(point x,const point &y) //向量减法
{ x.x-=y.x,x.y-=y.y;
return x; }
point operator *(const line &x,const line &y)//直线求交点
{ double a1=(y.b-x.a)*(y.a-x.a),a2=(y.a-x.b)*(y.b-x.b);
point r;
r.x=(x.a.x*a2+x.b.x*a1)/(a2+a1);
r.y=(x.a.y*a2+x.b.y*a1)/(a2+a1);
return r;
}
bool operator ==(const point &a,const point &b)//判断共点
{ return fabs(a.x-b.x)<EPS&&fabs(a.y-b.y)<EPS; }
bool operator <(const line &x,const line &y)//为极角排序重载的运算符
{
if(fabs(x.ang-y.ang)<EPS) return (y.b-x.a)*(x.b-y.a)>EPS;
return x.ang<y.ang;
}
bool judgeout(const line &x,const point &p)//判断点和平面的关系
{return (p-x.a)*(x.b-x.a)>EPS; }
bool parellel(const line &x,const line &y)//判断两个向量是否平行
{ return fabs((x.b-x.a)*(y.b-y.a))<-EPS; }
void inputdata()
{
scanf("%d",&n);
scanf("%lf%lf",&l[0].b.x,&l[0].b.y);
l[n-1].a.x=l[0].b.x,l[n-1].a.y=l[0].b.y;
for(int i=1;i<n;i++)
{
scanf("%lf%lf",&l[i].b.x,&l[i].b.y);
l[i-1].a.x=l[i].b.x,l[i-1].a.y=l[i].b.y;
}
for(int i=0;i<n;i++)
l[i].ang=atan2(l[i].b.y-l[i].a.y,l[i].b.x-l[i].a.x);
}
double hplaneintersection()
{
int top=1,bot=0;
sort(l,l+n); //极角排序
int tmp=1;
for(int i=1;i<n;++i)
if(l[i].ang-l[i-1].ang>EPS) l[tmp++]=l[i];//去重
n=tmp;
st[0]=l[0],st[1]=l[1];
for(int i=2;i<n;++i)
{
if(parellel(st[top],st[top-1])||parellel(st[bot],st[bot+1])) return 0;
while(bot<top&&judgeout(l[i],st[top]*st[top-1])) top--;
while(bot<top&&judgeout(l[i],st[bot]*st[bot+1])) bot++;
st[++top]=l[i];
}
while((bot<top&&judgeout(st[bot],st[top]*st[top-1]))) top--;
while((bot<top&&judgeout(st[top],st[bot]*st[bot+1])))bot++;
if(top<bot+1) return 0.00;
st[++top]=st[bot];
ccnt=0;
for(int i=bot;i<top;i++)
convex[ccnt++]=st[i]*st[i+1];
double ans=0;
convex[ccnt]=convex[0];
for(int i=0;i<ccnt;i++)
ans+=convex[i]*convex[i+1];
return ans/2;
}
double chackdirection()
{
double ans=0;
for(int i=0;i<n;++i)
ans+=l[i].a*l[i].b;
return ans;
}
void changedirection()
{
for(int i=0;i<n;++i)
swap(l[i].a,l[i].b);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
inputdata();
if(chackdirection()<0) changedirection();
printf("%.2f\n",hplaneintersection());
}
return 0;
}
code 2:
/*
半平面交。
解释下这个算法哈,其实用笔模拟一下就懂了。它是在一层一层缩小这个区域。
外层循环是用每一条边,筛选能看到它的点(或者说是内层形成的边吧),
如果看不到(也就是内层有边得两点在他的两侧),那么就求这条边和当前内层循环边的交点作为核的点。
交点是肯定能看到的啦。所以内层循环结束一次,点集就要变一次。
*/
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;
const int MAX = 1510;
struct point{ double x,y;};
point p[MAX],s[MAX];
const double eps = 1e-6;
bool dy(double x,double y) { return x > y + eps;} // x > y
bool xy(double x,double y) { return x < y - eps;} // x < y
bool dyd(double x,double y) { return x > y - eps;} // x >= y
bool xyd(double x,double y) { return x < y + eps;} // x <= y
bool dd(double x,double y) { return fabs( x - y ) < eps;} // x == y
double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向
{
return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y);
}
point l2l_inst_p(point u1,point u2,point v1,point v2)
{
point ans = u1;
double t = ((u1.x - v1.x)*(v1.y - v2.y) - (u1.y - v1.y)*(v1.x - v2.x))/
((u1.x - u2.x)*(v1.y - v2.y) - (u1.y - u2.y)*(v1.x - v2.x));
ans.x += (u2.x - u1.x)*t;
ans.y += (u2.y - u1.y)*t;
return ans;
}
void change_wise(point p[],int n)
{
for(int i=0; i<n/2; i++)
swap(p[i],p[n-i-1]);
}
void inst_hp(point p[],int n,point s[],int &len)
{
point tp[MAX];
p[n] = p[0];
for(int i=0; i<=n; i++)
tp[i] = p[i];
int cp = n,tc;
for(int i=0; i<n; i++)
{
tc = 0;
for(int k=0; k<cp; k++)
{
if( xyd(crossProduct(p[i],p[i+1],tp[k]),0.0) )// 顺时针的话是dyd
s[tc++] = tp[k];
if( xy(crossProduct(p[i],p[i+1],tp[k])*
crossProduct(p[i],p[i+1],tp[k+1]),0.0) )
s[tc++] = l2l_inst_p(p[i],p[i+1],tp[k],tp[k+1]);
}
s[tc] = s[0];
for(int k=0; k<=tc; k++)
tp[k] = s[k];
cp = tc;
}
len = cp;
}
double area_polygon(point p[],int n)
{
double s = 0.0;
for(int i=0; i<n; i++)
s += p[(i+1)%n].y * p[i].x - p[(i+1)%n].x * p[i].y;
return s/2.0;
}
int main()
{
int len,ncases,n;
scanf("%d",&ncases);
while( ncases-- )
{
scanf("%d",&n);
for(int i=0; i<n; i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
double area = area_polygon(p,n);
if( xyd(area,0.0) ) change_wise(p,n);
inst_hp(p,n,s,len);
double ans = area_polygon(s,len);
printf("%.2lf\n",fabs(ans));
}
return 0;