BZOJ 4077 Messenger
Messenger
【问题描述】
alice和bob各自在两条折线上行进,一个邮递员要从alice那拿一个包裹,并以直线移动到bob处,alice和bob、邮递员的速度均为1单位/s,问邮递员最少要走多少秒才能送完包裹。
【输入格式】
输入数据的第一行是一个整数na,代表alice运动轨迹的折线上的顶点数。
之后na行,每行两个整数,依次代表这个折线的第1号点、第2号点......第na号点的坐标。
之后一行是一个整数nb,代表bob运动轨迹的折线上的顶点数。
之后nb行,每行两个整数,依次代表这个折线的第1号点、第2号点......第nb号点的坐标。
na,nb目测是50000以内
【输出格式】
输出只有一行,一个小数,代表邮递员最少要走的时间。若无解,输出impossible
【样例输入】
2
0 0
0 10
2
4 10
4 0
【样例输出】
4.00000
题解:
考虑二分答案
让 Bob 提前走 mid,那么 Alice 与 Bob 的实时距离就是 快递员要走的时间
Check时不断移动,移动的距离是两个人分别与下一个点的距离中的较小值
问题变成了求实时距离(两个人有速度,在不同线段上运动)的最小值
我们以 Alice 为参考系,Bob 匀速移动,并且距离是不变的
就变成了求点(Allice所在位置)到直线(Bob的移动轨迹)的距离、
那么用点积判断是否组成锐角三角形,是的话用叉积求投影,否则就是点与直线两端点的较小值
无解的话 Check( Bob 的总路程) 一下就可以了
1 #include<cmath> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 using namespace std; 8 inline void Scan(int &x) 9 { 10 char c; 11 bool o = false; 12 while(!isdigit(c = getchar())) o = (c != '-') ? o : true; 13 x = c - '0'; 14 while(isdigit(c = getchar())) x = x * 10 + c - '0'; 15 if(o) x = -x; 16 } 17 const int maxn = 1e5; 18 const double inf = 2e10; 19 const double eps = 1e-8; 20 struct point 21 { 22 double x, y; 23 friend inline point operator + (point a, point b) 24 { 25 return (point) {a.x + b.x, a.y + b.y}; 26 } 27 friend inline point operator - (point a, point b) 28 { 29 return (point) {a.x - b.x, a.y - b.y}; 30 } 31 friend inline point operator * (point a, double x) 32 { 33 return (point) {a.x * x, a.y * x}; 34 } 35 friend inline point operator / (point a, double x) 36 { 37 return (point) {a.x / x, a.y / x}; 38 } 39 friend inline double operator * (point a, point b) 40 { 41 return a.x * b.y - a.y * b.x; 42 } 43 friend inline double operator ^ (point a, point b) 44 { 45 return a.x * b.x + a.y * b.y; 46 } 47 inline void print() 48 { 49 printf("x=%.2lf y=%.2lf\n", x, y); 50 } 51 }; 52 struct ele 53 { 54 int n; 55 double t; 56 point p; 57 void print() 58 { 59 printf("n=%d t=%.2lf ", n, t); 60 p.print(); 61 } 62 }; 63 inline double Sqr(double x) 64 { 65 return x * x; 66 } 67 inline double Dis(point a, point b) 68 { 69 return sqrt(Sqr(a.x - b.x) + Sqr(a.y - b.y)); 70 } 71 inline int Sgn(double x) 72 { 73 if(x < -eps) return -1; 74 if(x > eps) return 1; 75 return 0; 76 } 77 inline double Dis(point a, point b, point c) 78 { 79 if(Sgn(Dis(b, c))) 80 if(Sgn((a - b) ^ (c - b)) >= 0 && Sgn((a - c) ^ (b - c)) >= 0) 81 return fabs(((a - b) * (c - b)) / Dis(b, c)); 82 return min(Dis(a, b), Dis(a, c)); 83 } 84 struct thing 85 { 86 int n; 87 point p[maxn]; 88 double s[maxn]; 89 inline void Read() 90 { 91 Scan(n); 92 for(int i = 1; i <= n; ++i) 93 { 94 scanf("%lf%lf", &p[i].x, &p[i].y); 95 if(i > 1) s[i] = s[i - 1] + Dis(p[i], p[i - 1]); 96 } 97 } 98 }; 99 thing a, b; 100 inline point Pos(bool o, double x, int p) 101 { 102 if(o) return b.p[p] + (b.p[p + 1] - b.p[p]) * (x / (b.s[p + 1] - b.s[p])); 103 return a.p[p] + (a.p[p + 1] - a.p[p]) * (x / (a.s[p + 1] - a.s[p])); 104 } 105 point va, vb, dv; 106 inline double Mini(point a, point b, point c, point d, double dis) 107 { 108 va = (b - a) / Dis(a, b); 109 vb = (d - c) / Dis(c, d); 110 dv = vb - va; 111 d = c + dv * dis; 112 return Dis(a, c, d); 113 } 114 inline bool Check(double mid) 115 { 116 ele u, v; 117 u = (ele) {1, 0, a.p[1]}; 118 int n = upper_bound(b.s + 1, b.s + 1 + b.n, mid) - b.s - 1; 119 double s = mid - b.s[n]; 120 v = (ele) {n, s, Pos(true, s, n)}; 121 int x, y; 122 double l, r, res; 123 while(true) 124 { 125 if(Dis(u.p, v.p) < mid + eps) return true; 126 if(u.n == a.n || v.n == b.n) break; 127 x = u.n + 1, y = v.n + 1; 128 l = Dis(u.p, a.p[x]), r = Dis(v.p, b.p[y]); 129 res = Mini(u.p, a.p[x], v.p, b.p[y], min(l, r)); 130 if(res < mid + eps) return true; 131 if(!Sgn(l - r)) 132 { 133 u = (ele) {x, 0, a.p[x]}; 134 v = (ele) {y, 0, b.p[y]}; 135 continue; 136 } 137 if(l < r) 138 { 139 u = (ele) {x, 0, a.p[x]}; 140 v.t += l; 141 v.p = Pos(true, v.t, v.n); 142 } 143 else 144 { 145 u.t += r; 146 u.p = Pos(false, u.t, u.n); 147 v = (ele) {y, 0, b.p[y]}; 148 } 149 } 150 return false; 151 } 152 inline double Two() 153 { 154 int num = 50; 155 double mi; 156 double l = 0, r = b.s[b.n]; 157 while(num--) 158 { 159 mi = (l + r) / 2.0; 160 if(Check(mi)) r = mi; 161 else l = mi; 162 } 163 if(Check(l)) return l; 164 return r; 165 } 166 int main() 167 { 168 a.Read(); 169 b.Read(); 170 if(!(Check(b.s[b.n]))) 171 { 172 printf("impossible\n"); 173 return 0; 174 } 175 printf("%.5lf", Two()); 176 }