本题有向量做法,但因为要不断地将位置和时间相互转化,比较麻烦。
因为研究的对象是时间 (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
", r);
return 0;
}