Gym100851F Froggy Ford 最短路变形
网址:https://codeforces.com/gym/100851
题意:
在一段宽度为$w$的河上有$n$个石头,石头的位置确定,用坐标$(x,y)$表示,河左岸的方程是$x=0$,右岸的方程是$x=w$,有一只青蛙将从左岸沿着这些石头跳到右岸(不借助石头也可以),现在打算在这条河上再加一个石头,求出新的石头的位置,使得在加上这个石头后,青蛙通过这条河时路径上的跳跃的最大长度最小。
题解:
这个题也是套路题了,河的左岸和右岸一定是当成一点起点和一个终点。然后我们预处理出起点和终点到每个石头上的路径的边权最大值,用$dijkstra$求即可,转移方程是$dis[v]=max(dis[u],cur_edge)$。求的时候需要重新建图,因为不能从一个石头跳到起点\终点,再跳到另一个石头上。建完图之后我们求出了$diss和dist$。然后我们就求$min(max(diss[u],e(u->v),dist[v]))$,找到这个$u,v$。
有$4$种情况:
$u=$起点,$v!=$终点,则这个石头的坐标是$(\frac{x_v}{2},y)$。
$v=$终点,$u!=$起点,则这个石头的坐标是$(\frac{w+x_u}{2},y)$。
$u=$起点,$v=$终点,则这个石头的坐标是$(\frac{w}{2},0)$。
其他,则这个石头的坐标是$(\frac{x_u+x_v}{2},\frac{y_u+y_v}{2})$。
AC代码:
#include <bits/stdc++.h> using namespace std; const int N = 1e3 + 5; typedef long long ll; pair<double, double>p[N]; int n; double w; struct edge { int to; double w; bool operator <(const edge& a)const { return w > a.w; } }; vector<edge>G[N]; double len(pair<double, double>& a, pair<double, double>& b) { return sqrt((a.first - b.first) * (a.first - b.first) + (a.second - b.second) * (a.second - b.second)); } double dist[N], diss[N]; bool vis[N]; void dijkstra(int s, double* dis) { priority_queue<edge>q; for (int i = 0; i <= n + 1; ++i) dis[i] = 0x3f3f3f3f3f3f3f3f; memset(vis, 0, sizeof(vis)); q.push({ s,0 }); dis[s] = 0; while (q.size()) { edge cur = q.top(); q.pop(); if (vis[cur.to]) continue; vis[cur.to] = 1; for (auto i : G[cur.to]) if (max(dis[cur.to], i.w) < dis[i.to]) { dis[i.to] = max(dis[cur.to], i.w); q.push({ i.to,dis[i.to] }); } } } void init1() { for (int i = 0; i <= n + 1; ++i) G[i].clear(); for (int i = 1; i <= n; ++i) { G[0].push_back({ i,p[i].first }); G[i].push_back({ n + 1,w - p[i].first }); } for (int i = 1; i <= n; ++i) for (int j = i + 1; j <= n; ++j) { double d = len(p[i], p[j]); G[i].push_back({ j,d }); G[j].push_back({ i,d }); } } void init2() { for (int i = 0; i <= n + 1; ++i) G[i].clear(); for (int i = 1; i <= n; ++i) { G[n + 1].push_back({ i,w - p[i].first }); G[i].push_back({ 0,p[i].first }); } for (int i = 1; i <= n; ++i) for (int j = i + 1; j <= n; ++j) { double d = len(p[i], p[j]); G[i].push_back({ j,d }); G[j].push_back({ i,d }); } } int main() { #ifndef _Aya freopen("froggy.in", "r", stdin); freopen("froggy.out", "w", stdout); #endif scanf("%lf%d", &w, &n); for (int i = 1; i <= n; ++i) scanf("%lf%lf", &p[i].first, &p[i].second); init1(); dijkstra(0, diss); init2(); dijkstra(n + 1, dist); double maxn = 0x3f3f3f3f3f3f3f3f; double ansx = 0, ansy = 0; for (int i = 0; i <= n + 1; ++i) for (int j = 0; j <= n + 1; ++j) { double tmp; if (i == j) continue; if (i == 0 && j == n + 1) tmp = w; else if (i == 0) tmp = p[j].first; else if (j == n + 1) tmp = w - p[i].first; else tmp = len(p[i], p[j]); if (maxn > max(max(diss[i], tmp / 2), max(tmp / 2, dist[j]))) { maxn = max(max(diss[i], tmp / 2), max(tmp / 2, dist[j])); if (i == 0 && j != n + 1) ansx = p[j].first / 2, ansy = p[j].second; else if (i != 0 && j == n + 1) ansx = (p[i].first + w) / 2, ansy = p[i].second; else if (i == 0 && j == n + 1) ansx = w / 2, ansy = 0; else ansx = (p[i].first + p[j].first) / 2, ansy = (p[i].second + p[j].second) / 2; } } printf("%lf %lf\n", ansx, ansy); return 0; } /* 10 7 2 2 2 4 5 1 5 3 8 2 7 5 9 4 */