[XJOI NOI02015訓練題7] B 線線線 【二分】

題目連接:XJOI - NOI2015-07 - Bios

 

題目分析

題意:過一個點 P 的全部直線,與點集 Q 的最小距離是多少?一條直線與點集的距離定義爲點集中每一個點與直線距離的最大值。學習

題解:二分答案,對於一個二分的距離,咱們能夠求出對於每一個點的可用的極角範圍,而後判斷 n 個點的極角範圍有沒有交便可。spa

聽起來很是簡單..結果我發現細節很麻煩..3d

由於,極角的範圍是環形的,若是限定在 [-PI, PI] 的範圍內,跨越 -PI = PI 這條線的極角範圍就很難處理。blog

而後兩個環上的範圍的交多是兩段,也是很難處理..get

學習神犇的處理方式,對於每一個極角範圍,在左端點記上一個 1,右端點記上一個 -1,而後若是一個位置被 n 個區間包含,那麼這個位置的前綴和就是 n 。string

很是的和諧,看起來問題已經解決了...然而我發現神犇的作法仍是有些細節沒法理解..it

好比區間的範圍可能超出了 [-PI, PI] ....可是我已經想不清楚了...仍是記住這種處理方式吧io

照着神犇的代碼寫以後仍是 TLE 了 2 個點,最後改了改 Eps 讓二分次數減小了一些,終於過了。class

而且向下保留 3 位小數,我這樣寫 printf("%.3f\n", Ans - 0.0005); 就會 WA 掉 1 個點。

這樣寫 AnsN = (int)(Ans * 1000); printf("%d.%03d\n", 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\n", AnsN / 1000, AnsN % 1000);
	return 0;
}
相關文章
相關標籤/搜索