2023ICPC网络赛第一场K题

使用极坐标时可不要忘记乘r了

/*
https://blog.csdn.net/qq_34731703/article/details/53769806?
POJ: 1113 2318 1556 1696 2826 2074 1873 3252 2187 3608
LuoGu: 3187
*/
/*
floor();//向下取整  ceil();//向上取整  round();//四舍五入
判等时不要直接使用=
*/
//#include<bits/stdc++.h>
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const double pi = acos(-1.0);
const double inf = 1e100;
/*
误差判断
*/
const double eps = 1e-10;
//大小判断 
int dcmp(double x, double y){
    if(fabs(x - y) < eps)
        return 0;
    if(x > y)
        return 1;
    return -1;
}
//符号判断 
int sgn(double d){
    if(fabs(d) < eps)
        return 0;
    if(d > 0)
        return 1;
    return -1;
}
/*---------------------------------------------------------------------------------------*/
//点
struct Point{
	double x, y;
    Point(double x = 0, double y = 0):x(x),y(y){}
};
//向量
typedef Point Vector;
//运算
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);
}
Vector operator / (Vector A, double p){
    return Vector(A.x/p, A.y/p);
}
bool operator == (Point A,Point B){
	return sgn(A.x-B.x)==0&&sgn(A.y-B.y)==0;
}
bool P_cmp1(Point a,Point b){
    if(a.x==b.x)
    	return a.y<b.y;
    return a.x<b.x;
}
//向量数量积  向量α在向量β的投影于向量β的长度乘积(带方向)
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 Length(Vector A){
    return sqrt(Dot(A, A));
}
//计算夹角
double Angle(Vector A, Vector B){
    return acos(Dot(A, B) / Length(A) / Length(B));
}
//向量旋转
Vector Rotate(Vector A, double rad){//rad为弧度 且为逆时针旋转的角
    return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}
Vector Normal(Vector A){//向量A左转90°的单位法向量
    double L = Length(A);
    return Vector(-A.y/L, A.x/L);
}
//三角形外接圆圆心
Point Excenter(Point a, Point b, Point c){
    double a1 = b.x - a.x;
    double b1 = b.y - a.y;
    double c1 = (a1*a1 + b1*b1)/2;
    double a2 = c.x - a.x;
    double b2 = c.y - a.y;
    double c2 = (a2*a2 + b2*b2)/2;
    double d = a1*b2 - a2*b1;
    return Point(a.x + (c1*b2 - c2*b1)/d, a.y + (a1*c2 - a2*c1)/d);
}
//两点距离
double dis(Point a,Point b){
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double dis2(Point a,Point b){
	return ((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
//极角排序 
Point Tmp(0,0);//选好的起点
int Quadrant(Point a){// 象限
    if(a.x>0&&a.y>=0)  return 1;
    if(a.x<=0&&a.y>0)  return 2;
    if(a.x<0&&a.y<=0)  return 3;
    if(a.x>=0&&a.y<0)  return 4;
}
bool Polar_angle_cmp(Point a,Point b){
    if(Quadrant(a-Tmp)==Quadrant(b-Tmp)){
        double ans=Cross(a-Tmp,b-Tmp);
        if(ans==0)return a.x<b.x;
        return ans>0;
    }
    return Quadrant(a-Tmp)<Quadrant(b-Tmp);
}
/*------------------------------------------------------------------------------------------------*/
//线
struct Line{//直线定义
    Point v, p;
    Line(){}
    Line(Point v, Point p):v(v), p(p){}
};
//判断点是否在线上
bool PointOnline(Line A,Point a){
	Vector v1(A.p.x-a.x,A.p.y-a.y);
	Vector v2(A.v.x-a.x,A.v.y-a.y);
	return !(Cross(v1,v2));
}
//计算两直线交点 必须保证直线相交,否则将会出现除以零的情况
Point GetLineIntersection(Point a1, Point a2, Point b1, Point b2){
	Vector v = a1-a2;
	Vector w = b1-b2;
	Vector u = a1-b1;
    double t = Cross(w, u)/Cross(v, w);
    return a1+v*t;
}
//点P到直线AB距离公式
double DistanceToLine(Point P, Point A, Point B){
    Vector v1 = B-A, v2 = P-A;
    return fabs(Cross(v1, v2)/Length(v1));
}
//点A到线段BC距离公式
double DistanceToSegment(Point A, Point B, Point C){
    if(dis(B,C)<eps)       return dis2(A,B);
    if(Dot(B-C,A-C)<0)    return dis2(A,C);
    if(Dot(A-B,C-B)<0)    return dis2(A,B);
    return fabs((Cross(B-A,C-A)*Cross(B-A,C-A)/dis2(B,C)));
} 
//点P在直线AB上的投影点
Point GetLineProjection(Point P, Point A, Point B){
    Vector v = B-A;
    return A+v*(Dot(v, P-A)/Dot(v, v));
}
//判断点是否在线段上
bool OnSegment(Point p, Point a1, Point a2){
    return dcmp(Cross(a1-p, a2-p),0) == 0 && dcmp(Dot(a1-p, a2-p),0) <= 0;
}
//判断线段相交
bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2){
    double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1);
    double c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
    //if判断控制是否允许线段在端点处相交,根据需要添加
    if(!sgn(c1) || !sgn(c2) || !sgn(c3) || !sgn(c4)){
        bool f1 = OnSegment(b1, a1, a2);
        bool f2 = OnSegment(b2, a1, a2);
        bool f3 = OnSegment(a1, b1, b2);
        bool f4 = OnSegment(a2, b1, b2);
        bool f = (f1|f2|f3|f4);
        return f;
    }
    return (sgn(c1)*sgn(c2) < 0 && sgn(c3)*sgn(c4) < 0);
}
//点c是否在线段ab的左侧 左1 线上0 右-1
int ToLeftTest(Point a, Point b, Point c){
    if( Cross(b - a, c - b) > 0) return 1;
    else if( Cross(b - a, c - b) == 0) return 0;
    else return -1;
}
/*------------------------------------------------------------------------*/
//多边形
//求凸包 多边形p  凸包ch 
int ConvexHull(Point *p,int n,Point *ch){
	n=unique(p,p+n)-p;//去重
	sort(p,p+n,P_cmp1);//整理凸包 
	int v=0;
	for(int i=0;i<n;i++){ 
		while(v>1&&Cross(ch[v-1]-ch[v-2],p[i]-ch[v-1])<=0)
			v--;
		ch[v++]=p[i];
	}
	int j=v;
	for(int i=n-2;i>=0;i--){
		while(v>j&&Cross(ch[v-1]-ch[v-2],p[i]-ch[v-1])<=0)
			v--;
		ch[v++]=p[i];
	}
	if(n>1) v--;
	return v;
}
//逆时针排序:整理凸包
void anticlockwise_sort(Point* P,int N){
    for(int i=0;i<N-2;i++){
        int tmp=Cross(P[i+1]-P[i],P[i+2]-P[i]);
        if(tmp >0)
            return ;
        else if(tmp<0){
            reverse(P,P+N);
            return;
        }
    }
}
//求凸包周长
double CofCH(Point *ch,int m){
	double C=0;
	for(int i=0;i<m;i++)
		C+=dis(ch[i],ch[(i+1)%m]);
	return C;
}
//多边形有向面积
double PolygonArea(Point* 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;
}
//判断点是否在多边形内,若点在多边形内返回1,在多边形外部返回0,在多边形上返回-1
int isPointInPolygon(Point p, Point *poly,int n){
    int wn = 0;
    for(int i = 0; i < n; ++i){
        if(OnSegment(p, poly[i], poly[(i+1)%n])) return -1;
        int k = sgn(Cross(poly[(i+1)%n] - poly[i], p - poly[i]));
        int d1 = sgn(poly[i].y - p.y);
        int d2 = sgn(poly[(i+1)%n].y - p.y);
        if(k > 0 && d1 <= 0 && d2 > 0) wn++;
        if(k < 0 && d2 <= 0 && d1 > 0) wn--;
    }
    if(wn != 0)
        return 1;
    return 0;
}
//旋转卡壳
//求最远点对
double RTJ_PP(Point *poly,int n){
	poly[n]=poly[0];
	double res=0;
	for(int i=0,j=1;i<n;i++){
		while(Cross(poly[i]-poly[j],poly[i+1]-poly[j])<Cross(poly[i]-poly[j+1],poly[i+1]-poly[j+1]))
			j=(j+1)%n;
		res=max(res,max(dis(poly[i],poly[j]),dis(poly[i+1],poly[j])));
	}
	return res;
} 
//凸包最近点对 (算两次)
double PTJ_CHCH(Point *P,int N,Point *Q,int M){
	anticlockwise_sort(P,N);
	anticlockwise_sort(Q,M);
	int yminP=0,ymaxQ=0;
    for(int i=0;i<N;i++)    if(P[yminP].y>P[i].y)   yminP=i;
    for(int i=0;i<M;i++)    if(Q[ymaxQ].y<Q[i].y)   ymaxQ=i;
	P[N]=P[0];
    Q[M]=Q[0];
    double arg,ans=inf;
    for(int i=0;i<N;i++)//以P为主图形,以yminP为起点 所有点跑一圈
    {
        while(arg=Cross(P[yminP+1]-P[yminP],Q[ymaxQ+1]-P[yminP])-Cross(P[yminP+1]-P[yminP],Q[ymaxQ]-P[yminP])>0 )
            ymaxQ=(ymaxQ+1)%M;
        double asd=min(
		min(DistanceToSegment(P[yminP],Q[ymaxQ],Q[ymaxQ+1]),DistanceToSegment(P[yminP+1],Q[ymaxQ],Q[ymaxQ+1])),
		min(DistanceToSegment(Q[ymaxQ],P[yminP],P[yminP+1]),DistanceToSegment(Q[ymaxQ+1],P[yminP],P[yminP+1]))
		);
		ans=min(ans,asd);
        yminP=(yminP+1)%N;
	}
    return ans;
}
//求凸多边形最小面积外接矩阵
double PTJ_MAEM(Point *ch,int n,Point *MX){
	ch[n]=ch[0];
	double ans=inf;
	int j=1,k=1,l;
	for(int i=0;i<n;i++){
		//最上点 
		while(Cross(ch[i]-ch[j],ch[i+1]-ch[j])<=Cross(ch[i]-ch[j+1],ch[i+1]-ch[j+1]))
			j=(j+1)%n;
		//最左点
		while(Dot(ch[i+1]-ch[i],ch[k+1]-ch[i])>=Dot(ch[i+1]-ch[i],ch[k]-ch[i]))
			k=(k+1)%n;
		//最右点
		//1
		if(i==0)l=k;
		while(Dot(ch[i+1]-ch[i],ch[l+1]-ch[i])<=Dot(ch[i+1]-ch[i],ch[l]-ch[i]))	
			l=(l+1)%n;
		Point ll=GetLineProjection(ch[l],ch[i],ch[i+1]);
		Point kk=GetLineProjection(ch[k],ch[i],ch[i+1]);
		double h=DistanceToLine(ch[j],ch[i],ch[i+1]);
		double d=dis(ll,ch[i])+dis(ch[i],ch[i+1])+dis(kk,ch[i+1]);
		double cmp=h*d;
		if(ans>cmp){
			ans=cmp;
			MX[0]=ll,MX[1]=kk;
			MX[2]=kk+Normal(ch[i+1]-ch[i])*h;
			MX[3]=ll+Normal(ch[i+1]-ch[i])*h;
		}
	}
	return ans;	
} 
/*-----------------------------------------------------------------------------------*/
//半平面
struct Hplane{
	Point p;//直线上一点  
	Vector v;//方向向量 他的左边是半平面
	double ang;//极角
	Hplane(){};
	Hplane(Point p,Vector v):p(p),v(v){ang=atan2(v.y,v.x);}
	bool operator < (Hplane &L){return ang<L.ang;}//用于排序 
}; 
//p是否在半平面内 
bool OnLeft(Hplane L,Point p){return sgn(Cross(L.v,p-L.p))>0;}
//半平面交点 
Point Cross_point(Hplane a,Hplane b){
	Vector u=a.p-b.p;
	double t=Cross(b.v,u)/Cross(a.v,b.v);
	return a.p+a.v*t;
} 
//求半平面交凸包 
int HalfplaneIntersection(Hplane* L, int n, Point* poly){
    sort(L, L + n);//按照极角排序
    int fst = 0, lst = 0;//双端队列的第一个元素和最后一个元素
    Point *P = new Point[n];//p[i] 为 q[i]与q[i + 1]的交点
    Hplane *q = new Hplane[n];//双端队列
    q[fst = lst = 0] = L[0];//初始化为只有一个半平面L[0]
    for(int i = 1; i < n; ++i){
        while(fst < lst && !OnLeft(L[i], P[lst - 1])) --lst;
        while(fst < lst && !OnLeft(L[i], P[fst])) ++fst;
        q[++lst] = L[i];
        if(fabs(Cross(q[lst].v, q[lst - 1].v))<eps){//这里改了,更保证精度准确 
            //两向量平行且同向,取内侧一个
            --lst;
            if(OnLeft(q[lst], L[i].p)) q[lst] = L[i];
        }
        if(fst < lst)
            P[lst - 1] = Cross_point(q[lst - 1], q[lst]);
    }
    while(fst < lst && !OnLeft(q[fst], P[lst - 1])) --lst;
    //删除无用平面
    if(lst - fst <= 1)
		return 0;	
	//空集
    P[lst] = Cross_point(q[lst], q[fst]);//计算首尾两个半平面的交点
    //从deque复制到输出中
    int m = 0;
    for(int i = fst; i <= lst; ++i) poly[m++] = P[i];
    return m;
}
//将边往里推r的距离 
void PushIn(Hplane *poly,double r,int n,Hplane *C_poly){
	for(int i=0;i<n;i++){
		C_poly[i]=poly[i];
		C_poly[i].p=poly[i].p+Normal(poly[i].v)*r;
	}
}
/*------------------------------------------------------------------------------------------*/
//三维点
struct Point3{
	double x,y,z;
	Point3(){}
	Point3(double x,double y,double z):x(x),y(y),z(z){}
}; 
//三维向量
typedef Point3 Vector3;
//运算
Vector3 operator + (Vector3 A, Vector3 B){
    return Vector3(A.x+B.x, A.y+B.y,A.z+B.z);
}
Vector3 operator - (Vector3 A, Vector3 B){
    return Vector3(A.x-B.x, A.y-B.y,A.z-B.z);
}
Vector3 operator * (Vector3 A, double p){
    return Vector3(A.x*p, A.y*p,A.z*p);
}
Vector3 operator / (Vector3 A, double p){
    return Vector3(A.x/p, A.y/p,A.z/p);
}
bool operator == (Point3 A,Point3 B){
	return sgn(A.x-B.x)==0&&sgn(A.y-B.y)==0&&sgn(A.z-B.z);
}
//向量数量积  向量α在向量β的投影于向量β的长度乘积(带方向)
double Dot(Vector3 A, Vector3 B){
    return A.x*B.x + A.y*B.y+A.z*B.z;
}
//向量向量积  向量α与β所张成的平行四边形的有向面积
Vector3 Cross(Vector3 A, Vector3 B){
    return Point3(A.y*B.z-A.y*B.x,A.x*B.z-A.z*B.x,A.x*B.y-A.y*B.x);
}
//取模
double Length(Vector3 A){
    return sqrt(Dot(A, A));
}
//计算夹角
double Angle(Vector3 A, Vector3 B){
    return acos(Dot(A, B) / Length(A) / Length(B));
}
//两点距离
double dis(Point3 a,Point3 b){
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
//计算三角形面积*2
double Area2(Point3 A,Point3 B,Point3 C){
	return Length(Cross(B-A,C-A));
} 
/*-----------------------------------------------------------------------------------------*/
//三维线
struct Line3{
	Point3 p,v;
	Line3(){}
	Line3(Point3 p,Point3 v):p(p),v(v){}
}; 
//判断点是否在线上
bool PointOnline(Line3 A,Point3 a){
	return sgn(Length(Cross(A.p-a,A.v-a)))==0&&sgn(Dot(A.p-a,A.v-a))==0;
}
//点到直线的投影
Point3  GetLineProjection(Point3 p,Point3 a,Point3 b){
	double k=Dot(b-a,p-a)/Dot(b-a, b-a);
	return a+(b-a)*k;
} 
//点到直线的距离
double  DistanceToLine(Point3 p,Point3 a,Point3 b){
	return dis(p,GetLineProjection(p,a,b));
}
//点到线段的距离
double  DistanceToSegment(Point3 p,Point3 a,Point3 b){
	if(sgn(Dot(p-a,b-a))<0||sgn(Dot(p-b,a-b))<0){
		return min(dis(a,p),dis(b,p));
	}
	return DistanceToLine(p,a,b);
}
/*-----------------------------------------------------------------------------------*/
//面
struct Plane{
	Point3 p1,p2,p3;
	Vector3 Pvec;
	Plane(){}
	Plane(Point3 p1,Point3 p2,Point3 p3):p1(p1),p2(p2),p3(p3){
		Pvec=Cross(p2-p1,p3-p1);
	}
}; 
//求法向量
Vector3 GetPvec(Point3 p1,Point3 p2,Point3 p3){
	return Cross(p2-p1,p3-p1);
} 
Vector3 GetPvec(Plane f){
	return Cross(f.p2-f.p1,f.p3-f.p1);
} 
//四点共面
bool Four_point_coplanar(Point3 A,Point3 B,Point3 C,Point3 D){
	return sgn(Dot(GetPvec(A,B,C),D-A))==0;	
} 
//两平面平行
bool Parallel(Plane f1,Plane f2){
	return Length(Cross(GetPvec(f1),GetPvec(f2)))<eps;
} 
//两平面垂直
bool Vertical(Plane f1,Plane f2){
	return sgn(Dot(GetPvec(f1),GetPvec(f2)))==0;
}  
//直线与平面的交点
int Line_cross_plane(Line3 u,Plane f,Point3 &p){
	Point3 v=GetPvec(f);
	double x=Dot(v,u.v-f.p1);
	double y=Dot(v,u.p-f.p1);
	double d=x-y;
	if(sgn(x)==0&&sgn(y)==0)return -1;//u在f上
	if(sgn(d)==0)return 0;//平行
	p=((u.p*x)-(u.v*y))/d;
	return 1; 
} 
//求四面体体积*6
double volume4(Point3 a,Point3 b,Point3 c,Point3 d){
	return Dot(Cross(b-a,c-a),d-a);
} 
/*------------------------------------------------------------------*/
struct Circle{
	Point o;
	double r;
	Circle(){};
	Circle(Point a,Point b){
		o=(a+b)/2;
		r=dis(a,b)/2;
	}
};
/************************************************************************************/
Point p[5000],ch[5000];
int main()
{
	int n,q;
	cin>>n>>q;
	for(int i=0;i<n;i++)
		cin>>p[i].x>>p[i].y;
	int m=ConvexHull(p,n,ch);
//	for(int i=0;i<m;i++)
//		cout<<ch[i].x<<' '<<ch[i].y<<endl;
	while(q--)
	{
		Point a,b;
		cin>>a.x>>a.y>>b.x>>b.y;
		Circle c(a,b);
		double RR2=c.r*c.r/2;
		if(isPointInPolygon(c.o,ch,m)!=0)
		{
			printf("%.10lf\n",RR2);
			continue;
		}
		anticlockwise_sort(ch,m);
		ch[m]=ch[0];
		double ans=inf;
		//cout<<c.o.x<<' '<<c.o.y<<endl;
		for(int i=0;i<m;i++)
		{
			ans=min(ans,DistanceToSegment(c.o,ch[i],ch[i+1]));
			//cout<<ans<<endl;
		}
		printf("%.10lf\n",ans+RR2);
	}
} 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值