zoukankan      html  css  js  c++  java
  • [XJOI NOI02015训练题7] B 线线线 【二分】

    题目链接:XJOI - NOI2015-07 - B

    题目分析

    题意:过一个点 P 的所有直线,与点集 Q 的最小距离是多少?一条直线与点集的距离定义为点集中每个点与直线距离的最大值。

    题解:二分答案,对于一个二分的距离,我们可以求出对于每个点的可用的极角范围,然后判断 n 个点的极角范围有没有交即可。

    听起来非常简单..结果我发现细节很麻烦..

    因为,极角的范围是环形的,如果限定在 [-PI, PI] 的范围内,跨越 -PI = PI 这条线的极角范围就很难处理。

    然后两个环上的范围的交可能是两段,也是很难处理..

    学习神犇的处理方式,对于每个极角范围,在左端点记上一个 1,右端点记上一个 -1,然后如果一个位置被 n 个区间包含,那么这个位置的前缀和就是 n 。

    非常的和谐,看起来问题已经解决了...然而我发现神犇的做法还是有些细节无法理解..

    比如区间的范围可能超出了 [-PI, PI] ....但是我已经想不清楚了...还是记住这种处理方式吧

    照着神犇的代码写之后还是 TLE 了 2 个点,最后改了改 Eps 让二分次数减少了一些,终于过了。

    并且向下保留 3 位小数,我这样写 printf("%.3f ", Ans - 0.0005); 就会 WA 掉 1 个点。

    这样写 AnsN = (int)(Ans * 1000); printf("%d.%03d ", AnsN / 1000, AnsN % 1000); 才能 AC。

    代码

    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    #define Vector Point
    #define PI 3.14159265358979
    
    inline void Read_Int(int &Num)
    {
    	char c = getchar();
    	bool Neg = false;	
    	while (c < '0' || c > '9')
    	{
    		if (c == '-') Neg = true;
    		c = getchar();
    	}
    	Num = c - '0'; c = getchar();
    	while (c >= '0' && c <= '9')
    	{
    		Num = Num * 10 + c - '0';
    		c = getchar();
    	}
    	if (Neg) Num = -Num;
    }
    
    typedef double LF;
    
    inline LF gmin(LF a, LF b) {return a < b ? a : b;}
    inline LF gmax(LF a, LF b) {return a > b ? a : b;}
    inline LF Sqr(LF x) {return x * x;}
    
    const LF Eps = 1e-6;
    
    const int MaxN = 111111 + 5;
    
    int n, Top, Tot;
    
    LF dis[MaxN], ta[MaxN];
    
    struct ES
    {
    	LF Pos;
    	int Num;
    	ES() {}
    	ES(LF a, int b) {Pos = a; Num = b;}
    } EQ[MaxN * 4];
    
    inline bool Cmp(ES e1, ES e2)
    {
    	return e1.Pos < e2.Pos;
    }
    
    struct Point
    {
    	LF x, y;
    	Point() {}
    	Point(LF a, LF b) {x = a; y = b;}
    	
    	void Read()
    	{
    		int a, b;
    		Read_Int(a); Read_Int(b);
    		x = (LF)a; y = (LF)b;
    	}
    } Px, P[MaxN];
    
    inline LF Dis(Point p1, Point p2)
    {
    	return sqrt(Sqr(p1.x - p2.x) + Sqr(p1.y - p2.y));
    }
    
    bool Check(LF d)
    {
    	LF l, r, t;
    	Top = 0; Tot = n;
    	for (int i = 1; i <= n; ++i)
    	{
    		if (dis[i] <= d) 
    		{	
    			--Tot;
    			continue;
    		}
    		t = asin(d / dis[i]);
    		l = ta[i] - t;
    		r = ta[i] + t;
    		EQ[++Top] = ES(l, 1);
    		EQ[++Top] = ES(r, -1);
    		if (ta[i] > 0)
    		{
    			EQ[++Top] = ES(l - PI, 1);
    			EQ[++Top] = ES(r - PI, -1);
    		}
    		else
    		{
    			EQ[++Top] = ES(l + PI, 1);
    			EQ[++Top] = ES(r + PI, -1);
    		}
    	}
    	if (Top == 0) return true;
    	int Cnt = 0;
    	sort(EQ + 1, EQ + Top + 1, Cmp);
    	for (int i = 1; i <= Top; ++i)
    	{
    		Cnt += EQ[i].Num;
    		if (Cnt == Tot) return true;
    	}
    	return false;
    }
    
    int main()
    {
    	scanf("%d", &n);
    	Px.Read(); 
    	for (int i = 1; i <= n; ++i) 
    	{
    		P[i].Read();
    		dis[i] = Dis(P[i], Px);
    		ta[i] = atan2(P[i].y - Px.y, P[i].x - Px.x);
    	}
    	LF l, r, mid, Ans;
    	l = 0; r = 2000000;
    	while (r - l >= Eps)
    	{
    		mid = (l + r) / 2.0;
    		if (Check(mid))
    		{
    			Ans = mid;
    			r = mid - Eps;
    		}
    		else l = mid + Eps;
    	}
    	int AnsN = (int)(Ans * 1000);
    	printf("%d.%03d
    ", AnsN / 1000, AnsN % 1000);
    	return 0;
    }
    

      

  • 相关阅读:
    LintCode "Maximum Gap"
    LintCode "Wood Cut"
    LintCode "Expression Evaluation"
    LintCode "Find Peak Element II"
    LintCode "Remove Node in Binary Search Tree"
    LintCode "Delete Digits"
    LintCode "Binary Representation"
    LeetCode "Game of Life"
    LintCode "Coins in a Line"
    LintCode "Word Break"
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4593033.html
Copyright © 2011-2022 走看看