半平面交模板

题目:按顺序给出多边形的点 问你是否有核?核的面积? 

半平面交:

1.把输入点的顺序捋成逆时针

2.对所有边排序 极角小的在前 极角相同最右边的方最前面

3.根据2的排序去重

4.模拟双端队列求出构成核的直线集合:每次判断前两条边的交点在当前边的右边与否

5.判断双端队列里元素的个数 >=3 YES 为啥子双端队列呢 因为极角排序这其实是个环 所以记得判一下首尾连接处。

6.齐活 NICE!

核的面积:

求直线集合的交点 然后直接求多边形面积不多说了qaq

上代码!

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const int MaxN = 105;

int n;
struct Point{
	double x,y;
	Point(double x = 0,double y = 0) : x(x),y(y) {}
}a[MaxN];
typedef Point Vector;

struct Line{
	Point s,e;
	Line() {}
	Line(Point a,Point b){ s = a,e = b;}
}L[MaxN],que[MaxN];//双端队列

int dcmp(double x){//equal ?= 0
	if(fabs(x) < eps) return 0;
	else return x < 0 ? -1:1;
}

//运算符重载
Vector operator + (Vector A, Vector B){ return Vector(A.x+B.x, A.y+B.y); }
Vector operator - (Vector A, Vector B){ return Vector(A.x-B.x, A.y-B.y); }
Vector operator * (Vector A, double p){ return Vector(A.x*p, A.y*p); }
bool operator == (const Point &a, const Point &b){
	return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
}

double Dot(Vector A, Vector B){ return A.x*B.x + A.y*B.y; }
double Cross(Vector A, Vector B){ return A.x*B.y - A.y*B.x; }

//得到极角角度
double getAngle(Vector a){
	return atan2(a.y,a.x);
}
double getAngle(Line a){
	return atan2(a.e.y - a.s.y,a.e.x - a.s.x);
}

//极角排序+同极角最左边拍在最后->去重
bool cmp(Line a,Line b){
	Vector va = a.e - a.s,vb = b.e - b.s;
	double A = getAngle(va),B = getAngle(vb);
	if(!dcmp(A - B)) return Cross(va,b.e - a.s) > 0;//右优先
	return A < B;
}

bool clockwise(){//?顺时针
	double ans = 0.0;
	for(int i = 1;i <= n - 2; i++){
		ans += Cross(a[i] - a[0],a[i + 1] - a[0]);
	}
	if(dcmp(ans) > 0) return false;
	return true;
}

Point Ist_L(Line a,Line b){//给两直线求交点
	double a1 = a.s.y - a.e.y,b1 = a.e.x - a.s.x,c1 = a.s.x * a.e.y - a.e.x * a.s.y;
	double a2 = b.s.y - b.e.y,b2 = b.e.x - b.s.x,c2 = b.s.x * b.e.y - b.e.x * b.s.y;
	return Point((c1*b2 - c2*b1)/(a2*b1 - a1*b2), (a2*c1 - a1*c2)/(a1*b2 - a2*b1));
}

bool OnRight(Line a,Line b,Line c){//bc交点?在a的左边
	Point o = Ist_L(b,c);
	return Cross(a.e - a.s,o - a.s) < 0;//a.s是zhou o在右边
}

double S_core(int head,int tail){//核面积
	double ans = 0.0;
	Point P[MaxN];
	que[tail] = que[head];
	int m = 0;
	for(int i = head;i < tail; i++){
		P[m++] = Ist_L(que[i],que[i + 1]);
	}
	P[m] = P[0];
	for(int i = 0;i < m; i++){
		ans += Cross(P[i] - P[0],P[i + 1] - P[0]);
	}
	if(dcmp(ans) < 0) ans *= -1.0;
	return ans / 2.0;
}

bool HalfPlane(){//半平面交 判断多边形是否有核
	sort(L,L + n,cmp);
	int head = 0,tail = 0,cnt = 0;//双端队列
	for(int i = 0;i < n - 1; i++){
		//去重 极角相同右边优先排序 所以取最后一个(最左边)
		if(!dcmp(getAngle(L[i]) - getAngle(L[i + 1]))) continue;
		L[cnt++] = L[i];
	}
	L[cnt++] = L[n - 1];

	for(int i = 0;i < cnt;i++){
		//删去较陡边
		while(tail - head > 1 && OnRight(L[i],que[tail - 1],que[tail - 2])) tail--;
		while(tail - head > 1 && OnRight(L[i],que[head],que[head + 1])) head++;
		que[tail++] = L[i];
	}
	//判断首尾(环)连接处的影响
	while(tail - head > 1 && OnRight(que[head],que[tail - 1],que[tail - 2])) tail--;
	while(tail - head > 1 && OnRight(que[tail - 1],que[head],que[head + 1])) head++;
	if(tail - head < 3) return false;
	return true;
}

int main()
{
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i = 0;i < n; i++){
			scanf("%lf %lf",&a[i].x,&a[i].y);
		}
		if(!clockwise()){
			for(int i = 0;i < n; i++){
				L[i] = Line(a[i],a[(i + 1) % n]);
			}//n - 1条线
		}
		else{
			a[n] = a[0];
			for(int i = 0;i < n; i++){
				L[i] = Line(a[n - i],a[n - i - 1]);
			}
		}
		if(HalfPlane()) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值