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
*/

 

posted @ 2020-03-28 20:48  Aya_Uchida  阅读(223)  评论(0编辑  收藏  举报