[题解] 航班通信

本题有向量做法,但因为要不断地将位置和时间相互转化,比较麻烦。

因为研究的对象是时间 \(t\),可以建立 \(x, y\) 关于 \(t\) 的参数方程,这样可以表示出任意直线。

显然二分答案 \(r\),需要求出直线和点,点和点之间距离在 \(r\) 以内的区间,然后对于每个点暴力建图检测。

直接解二次方程得出两个距离为 \(r\) 的位置,注意要特判 \(\Delta<0\),两线平行的情况。

然后注意处理下航线开始,结束的时间就好,写的时候要注意细节。卡了一天

复杂度 \(\mathcal O(n + m)^4\)

Code

函数 KBRSolve 求解 \((k_1t+b_1)^2 + (k_2t + b_2)^2 - r^2 = 0\)

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

#define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
template<class T> void upmax(T &x, T y){x = x>y ? x : y;}
template<class T> void upmin(T &x, T y){x = x<y ? x : y;}

const int N = 105;
const double eps = 1e-6;
int n, m;
double x[N], y[N];
double kx[N], bx[N], ky[N], by[N];
double t1[N], t2[N];

double equal(double x, double y = 0) {return fabs(x - y) < eps;}
double sq(double x) {return x * x;}
pair<double, double> quadSolve(double a, double b, double c){
	if(a == 0) return {-c / b, -c / b};
	double delta = b * b - 4 * a * c;
	if(-1e-8 < delta && delta < 0) delta = 0;
	if(delta < 0) return {0, -1};
	else{
		delta = sqrt(delta);
		return {(-b - delta) / (2 * a), (-b + delta) / (2 * a)};
	}
}
pair<double, double> KBRSolve(double k1, double b1, double k2, double b2, double r){
	return quadSolve(
		sq(k1) + sq(k2),
		2 * (k1 * b1 + k2 * b2),
		sq(b1) + sq(b2) - sq(r)
	);
}

bool G[N][N], vis[N];

void dfs(int x){
	vis[x] = true;
	for(int j=n+1, li=n+m; j<=li; j++)
		if(G[x][j] && !vis[j]) dfs(j);
}

bool check(double r){
	struct Event{
		double t;
		int u, v;
		Event() {}
		Event(double Time, int U, int V) : t(Time), u(U), v(V) {}
	};
	static Event ev[N * N * 2];
	int ec = 0;
	for(int i=1; i<=n; i++)
		for(int j=1; j<=m; j++){
			auto R = KBRSolve(kx[j], bx[j] - x[i], ky[j], by[j] - y[i], r);
			if(R.first - R.second < eps){
				upmax(R.first, t1[j]);
				upmin(R.second, t2[j]);
				if(R.first - R.second > -eps) continue;
				ev[++ec] = Event(R.first, i, j + n);
				ev[++ec] = Event(R.second, -i, -j - n);
			}
		}
	for(int i=1; i<=m; i++)
		for(int j=i+1; j<=m; j++){
			pair<double, double> R;
			if(equal(kx[i] * ky[j], kx[j] * ky[i])){
				if(sqrt(sq(bx[i] - bx[j]) + sq(by[i] - by[j])) - r < eps) R = {max(t1[i], t1[j]), min(t2[i], t2[j])};
				else R = {0, -1};
			}
			else R = KBRSolve(kx[j] - kx[i], bx[j] - bx[i], ky[j] - ky[i], by[j] - by[i], r);
			if(R.first + eps < R.second){
				upmax(R.first, max(t1[i], t1[j]));
				upmin(R.second, min(t2[i], t2[j]));
				if(R.first + eps > R.second) continue;
				ev[++ec] = Event(R.first, i + n, j + n);
				ev[++ec] = Event(R.second, -i - n, -j - n);
			}
		}
	sort(ev + 1, ev + 1 + ec, [](const Event &a, const Event &b){
		return a.t < b.t;
	});
	for(int i=1; i<=ec; i++){
		int u = ev[i].u, v = ev[i].v;
		if(u > 0) G[u][v] = G[v][u] = true;
		else G[-u][-v] = G[-v][-u] = false;
		fill_n(vis + 1, n + m, false);
		for(int j=1; j<=n; j++) dfs(j);
		for(int j=1; j<=m; j++)
			if(t1[j] - ev[i].t < -eps && ev[i].t - t2[j] < -eps && !vis[j + n]) return false;
	}
	return true;
}

int main(){
	scanf("%d%d", &n, &m);
	for(int i=1; i<=n; i++)
		scanf("%lf%lf", x + i, y + i);
	for(int i=1; i<=m; i++){
		int s, t;
		scanf("%d%d%lf%lf", &s, &t, t1 + i, t2 + i); ++s; ++t;
		kx[i] = (x[t] - x[s]) / (t2[i] - t1[i]);
		bx[i] = x[s] - t1[i] * kx[i];
		ky[i] = (y[t] - y[s]) / (t2[i] - t1[i]);
		by[i] = y[s] - t1[i] * ky[i];
	}
	double l = 0, r = sqrt(2e6) / 2, mid;
	while(r - l > 1e-5){
		mid = (l + r) / 2;
		if(check(mid)) r = mid;
		else l = mid;
	}
	printf("%.4lf\n", r);
	return 0;
}
posted @ 2020-05-17 17:50  RiverHamster  阅读(144)  评论(0编辑  收藏  举报
\