标签:面积 一段 dig ring sort 逆时针 计算几何 abs 入队
叉积
a到b顺时针则为正,逆时针则为负(把a顺时针方向转到b的方向,夹角为 θ。当 0≤θ<π时值为正;当π≤θ<2π时值为负。
极角排序
atan2 返回(\(-\pi\),\(\pi\)),值等于arctan
直线交点
用一条直线的起点+一段向量,用面积比求比例,画两条线段手推
确定左半平面还是右半平面(最好写左半平面)
排序函数,先按斜率排序,否则靠近可行域的在前面
每次加入新直线,去掉交点在要求的一侧的异侧(右边)的那个直线,前后都要去,可以存交点
最后用队头去一下队尾
代码实现
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int read(){
int x=0,pos=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch==‘-‘) pos=0;
for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-‘0‘;
return pos?x:-x;
}
const int N = 3e5+500;
#define db double
const double eps= 1e-15;
const db inf = 1e18;
using namespace std;
struct point{
db x,y;
point (double x=0,double y=0): x(x),y(y){}
db operator *(point b){
return x*b.y-y*b.x;
}
db operator ^(point b){
return x*b.x+y*b.y;
}
point operator -(point b){
return point(x-b.x,y-b.y);
}
point operator +(point b){
return point(x+b.x,y+b.y);
}
point operator *(db b){
return point (x*b,y*b);
}
db dis(){
return sqrt(x*x+y*y);
}
}p[N],t[N];
int comp0(db x){
return fabs(x)<=eps?0:(x>0?1:-1);
}
struct line{
point p,v;
line(point p=point(0,0),point v=point(0,0)) :p(p),v(v){}
double k;
void getk(){
k=atan2((v.y-p.y),(v.x-p.x));//y/x
}
const int operator <(line y)const{
return comp0(k-y.k)==0?((y.p-p)*(y.v-p)>-eps):(k<y.k);斜率/位置*
}
}s[N],q[N];
int n,top;
point inter(line a,line b){
point v1=a.v-a.p,v2=b.v-b.p;
return b.p+v2*(((b.p-a.p)*v1)/(v1*v2));//面积比例法
}
void work(){
sort(s+1,s+top+1);
int r=0,l=1;
for(int i=1;i<=top;i++){
if(comp0(s[i].k-s[i-1].k)){//入斜率一样就跳过,排序一定要排好
while(l<r&&(s[i].v-t[r])*(s[i].p-t[r])>eps) r--;//先从后面去掉一些直线
while(l<r&&(s[i].v-t[l+1])*(s[i].p-t[l+1])>eps) l++;//再从前面限制
q[++r]=s[i];//加入队尾
if(l<r) t[r]=inter(q[r],q[r-1]);//求交点
}
}
while(r>l&&(q[l].v-t[r])*(q[l].p-t[r])>eps) r--;
t[r+1]=inter(q[r],q[l]);r++;//记得最后一条边和第一条边有交点
return 0;
}
标签:面积 一段 dig ring sort 逆时针 计算几何 abs 入队
原文地址:https://www.cnblogs.com/lcyfrog/p/12742090.html