Codefroces 250D. Building Bridge (数学思维)

来源:互联网 发布:疯狂java讲义在线 编辑:程序博客网 时间:2024/05/17 23:36

点击打开链接

题意就是,一个坐标轴上,一个西边村庄在(0,0),然后有一条河在x=a和x=b夹着的地方(a < b),西边村庄有n条路到达a河岸纵坐标为y的路,都是直路。x=b的右边有一个村庄,有m条路到达河岸b,但是这些路不是直的,只知道这些路各自的长度是L。现在要你在河岸两边选一点,建一座桥,使得西边村庄到东边村庄的距离最短。输出选西边哪个点和东边哪个点来建桥。

解法:真的是想了两三个小时没有想出来怎么做好。。。然后找了个题解。大致就是,两点之间直线最短。选取b河岸上一点,他所能到达a的方式最优的只有一条路,选取a河岸上的点肯定是最靠近它和东边村庄的连线的那个点,两点之间直线最短嘛。所以我们将a河岸上的点排一下序。枚举b河岸上的点,然后不断找a河岸上离当前枚举的点和东边村庄的连线最近的点来更新答案即可。复杂度O(mlogn)。

代码如下:

#include<cstdio>#include<cmath>#include<algorithm>#include<vector>using namespace std;typedef pair<double, int> pii;const int maxn = 1e5 + 5;const double eps = 1e-10;int n, m;double a[maxn], b[maxn], l[maxn];vector <pii> v;double Count(double x1, double y1, double x2, double y2) {return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));}int main() {#ifndef ONLINE_JUDGEfreopen("in.txt", "r", stdin);//    freopen("out.txt", "w", stdout);#endifint ans1, ans2;double x1, x2;scanf("%d%d%lf%lf", &n, &m, &x1, &x2);for(int i = 0; i < n; i++) {scanf("%lf", &a[i]);v.push_back(pii(a[i], i));}for(int i = 0; i < m; i++) {scanf("%lf", &b[i]);}for(int i = 0; i < m; i++) {scanf("%lf", &l[i]);}sort(a, a + n);sort(v.begin(), v.end());double Min = 1e18;for(int i = 0; i < m; i++) {double k = b[i] / x2;double y = k * x1;int p = lower_bound(a, a + n, y) - a;if(p < n) {double tmp = Count(0, 0, x1, a[p]) + Count(x1, a[p], x2, b[i]) + l[i];if(Min - tmp > eps) {Min = tmp;ans1 = v[p].second;ans2 = i;}}if(p - 1 >= 0) {double tmp = Count(0, 0, x1, a[p - 1]) + Count(x1, a[p - 1], x2, b[i]) + l[i];if(Min - tmp > eps) {Min = tmp;ans1 = v[p - 1].second;ans2 = i;}}}//printf("%f\n", Min);printf("%d %d\n", ans1 + 1, ans2 + 1);return 0;}