网址: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
", ansx, ansy);
return 0;
}
/*
10 7
2 2
2 4
5 1
5 3
8 2
7 5
9 4
*/