zoukankan      html  css  js  c++  java
  • 【题解】 保镖 半平面交

    Legend

    Link ( extrm{to HOJ})

    (校内 OJ 题目不公开)

    Editorial

    这个题神仙就神仙在这里:如果你是从观测者的角度,判断这个位置合不合法,这是非常难的。

    但如果你是从方向的角度来看,判断位置合不合法,就非常简单——因为这会形成一个半平面。

    先不考虑方向的连续性,我们枚举一个方向 ( heta),计算人往这个方向走过去,能接近一队保镖的半平面是什么。

    然后我们把所有半平面交起来就是答案,也就是对于所有方向都合法的那些位置。

    现在的问题就是怎么把方向变成离散的。——提取出真正有有用的角度

    不难发现真正有用的角度就是所有点的两两连线。

    复杂度 (O(n^3))

    Code

    #include <bits/stdc++.h>
    
    #define debug(...) ;//fprintf(stderr ,__VA_ARGS__)
    #define __FILE(x)
    	freopen(#x".in" ,"r" ,stdin);
    	freopen(#x".out" ,"w" ,stdout)
    #define LL long long
    
    const int MX = 100 + 3;
    const LL MOD = 998244353;
    const double eps = 1e-10;
    
    int read(){
    	char k = getchar(); int x = 0 ,flg = 1;
    	while(k < '0' || k > '9') flg *= (k == '-' ? -1 : 1) ,k = getchar();
    	while(k >= '0' && k <= '9') x = x * 10 + k - '0' ,k = getchar();
    	return x * flg;
    }
    
    struct VECTOR{
    	double x ,y;
    	VECTOR(double X = 0.0 ,double Y = 0.0){x = X ,y = Y;}
    	VECTOR operator +(const VECTOR& B)const{return VECTOR(x + B.x ,y + B.y);}
    	VECTOR operator -(const VECTOR& B)const{return VECTOR(x - B.x ,y - B.y);}
    	VECTOR operator -(int)const{return VECTOR(-x ,-y);}
    	double operator *(const VECTOR& B)const{return x * B.y - y * B.x;}
    	VECTOR operator *(const double& B)const{return VECTOR(x * B ,y * B);}
    	VECTOR operator /(const double& B)const{return VECTOR(x / B ,y / B);}
    	bool operator ==(const VECTOR& B)const{return fabs(x - B.x) < eps && fabs(y - B.y) < eps;}
    	void output()const{debug("(%.10lf ,%.10lf)
    " ,x ,y);}
    }A[MX] ,B[MX] ,inter[MX * MX];
    
    int lcnt;
    struct SEG{
    	VECTOR s ,d;
    	SEG(){s = d = VECTOR(0.0 ,0.0);}
    	SEG(VECTOR ST ,VECTOR END){s = ST ,d = END - ST;}
    	void output(){debug("(%lf ,%lf)->(%lf ,%lf)
    " ,s.x ,s.y ,(s+d).x ,(s+d).y);}
    }lim[MX * MX] ,q[MX * MX];
    
    VECTOR intersec(SEG A ,SEG B){
    	double s1 = A.d * (B.s - A.s);
    	double s2 = (B.s + B.d - A.s) * A.d;
    	return ((B.s + B.d) * s1 + B.s * s2) / (s1 + s2);
    }
    
    int quadrant(VECTOR 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;
    	return 0;
    }
    
    LL sgn(double A){return fabs(A) > eps ? (A > 0 ? 1 : -1) : 0;}
    
    bool sameDir(VECTOR A ,VECTOR B){
    	return sgn(A.x) == sgn(B.x) && sgn(A.y) == sgn(B.y) && fabs(A * B) < eps;
    }
    
    bool Left(SEG A ,VECTOR B){ // 查看点 B 是不是在 A 线段左侧
    	return A.d * (B - A.s) > eps;
    }
    
    bool Right(SEG A ,VECTOR B){
    	return (B - A.s) * A.d > eps;
    }
    
    bool cmp(SEG A ,SEG B){
    	int q1 = quadrant(A.d) ,q2 = quadrant(B.d);
    	if(q1 != q2) return q1 < q2;
    	if(A.d.x * B.d.y == A.d.y * B.d.x){
    		return Left(B ,A.s);
    	}
    	return A.d * B.d > 0;
    }
    
    int n ;
    bool TRY(SEG T){
    	VECTOR test(0 ,0);
    	if(test == T.d) return 0;
    	for(int i = 1 ; i <= n ; ++i){ // 不存在一条线段完全在它右侧
    		if(Right(T ,A[i]) && Right(T ,B[i])) return 0;
    	}
    	return 1;
    }
    
    int main(){
    	__FILE(b);
    	n = read();
    	for(int i = 1 ; i <= n ; ++i){
    		double x1 = read() ,y1 = read() ,x2 = read() ,y2 = read();
    		// x1 += 1e-11 ,x2 -= 1e-11;
    		// y1 += 1e-11 ,y2 -= 1e-11;
    		A[i] = VECTOR(x1 ,y1);
    		B[i] = VECTOR(x2 ,y2);
    	}
    
    	for(int i = 1 ; i <= n ; ++i){
    		for(int j = 1 ; j <= n ; ++j){
    			SEG T;
    			if(TRY(T = SEG(A[i] ,B[j]))){
    				lim[++lcnt] = SEG(T);
    				T.output();
    			}
    			if(i != j && TRY(T = SEG(A[i] ,A[j]))){
    				lim[++lcnt] = SEG(T);
    				T.output();
    			}
    			if(i != j && TRY(T = SEG(B[i] ,B[j]))){
    				lim[++lcnt] = SEG(T);
    				T.output();
    			}
    			if(TRY(T = SEG(B[j] ,A[i]))){
    				lim[++lcnt] = SEG(T);
    				T.output();
    			}
    		}
    	}
    
    	int tmpf = 1;
    	std::sort(lim + 1 ,lim + 1 + lcnt ,cmp);
    	for(int i = 2 ; i <= lcnt ; ++i){
    		if(sameDir(lim[i].d ,lim[i - 1].d));
    		else lim[++tmpf] = lim[i];
    	}
    
    	lcnt = tmpf;
    	int head = 1 ,tail = 1;
    	q[1] = lim[1];
    	for(int i = 2 ; i <= lcnt ; ++i){
    		while(head < tail && !Left(lim[i] ,inter[tail - 1])) --tail;
    		while(head < tail && !Left(lim[i] ,inter[head])) ++head;
    		q[++tail] = lim[i];
    		if(head < tail) inter[tail - 1] = intersec(q[tail - 1] ,q[tail]);
    	}
    	while(head < tail && !Left(q[head] ,inter[tail - 1])) --tail;
    	if(head < tail) inter[tail] = intersec(q[head] ,q[tail]);
    
    	double Ans = 0;
    	if(tail - head + 1 < 3) Ans = 0;
    	else{
    		for(int i = head ; i <= tail ; ++i)
    			inter[i].output();
    		for(int i = head + 1 ; i < tail ; ++i){
    			Ans += (inter[i] - inter[head]) * (inter[i + 1] - inter[head]);
    		}
    		Ans = fabs(Ans) / 2;
    	}
    	printf("%.10lf
    " ,Ans);
    
    	return 0;
    }
    
  • 相关阅读:
    Kafka 入门(四)-- Python Kafka Client 性能测试
    XShell连接阿里云服务器出现”用户密钥加载失败:请确定输入的密码“处理办法
    优化自动化测试流程,使用 flask 开发一个 toy jenkins工具
    我做了回视频,告诉你需要用到哪些工具
    提问的基本原则
    12 月31 日返利系统问题复盘
    外部prometheus监控k8s(k3s)集群
    一个Java类在运行时候,变量是怎么在JVM中分布的呢?
    JVM学习第二篇思考:一个Java代码是怎么运行起来的-下篇
    JVM学习第一篇思考:一个Java代码是怎么运行起来的-上篇
  • 原文地址:https://www.cnblogs.com/imakf/p/14449423.html
Copyright © 2011-2022 走看看