1. 程式人生 > 實用技巧 >Star Way To Heaven 題解

Star Way To Heaven 題解

題目連結

分析

此題可以暴力二分,但是隻有80pts,所以不採納這個思想。
考慮與最小生成樹的關係,當所有的引力把能走的路全部封死之後,此時的\(ans\)便是最大的引力圈的半徑。

step1

首先初始化\(dis[i] = m - y[i]\),把dis[k+1]設為m。

step2

然後用\(Prim\)不停遍歷,如果此時找的最近節點為\(k+1\)說明已經遍歷完畢,直接退出,
ans更新成ans與dis[falg]之間的大者。
然後更xin\(dis[i](i∈k)\), 更新\(dis[k+1]=min(dis[k+1], y[falg])\)
最後輸出\(ans/2\)

程式碼

#include <cmath> 
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 6005;
const int MAXM = 1e6 + 5;

int n, m, k;
double x[MAXN], y[MAXN], dis[MAXN], ans;
bool vis[MAXN];

double Dist(int u, int v) {
	return sqrt((x[u] - x[v]) * (x[u] - x[v]) + (y[u] - y[v]) * (y[u] - y[v]));
}

int main() {
	scanf ("%d %d %d", &n, &m, &k);
	for (int i = 1; i <= k; i++) {
		scanf ("%lf %lf", &x[i], &y[i]);
		dis[i] = (m * 1.0) - y[i]; 
	}
	dis[k + 1] = m;
	dis[0] = INF;
	ans = -1;
	while (1) {
	        int flag = 0;
		for (int i = 1; i <= k + 1; i++) {
			if (vis[i] == 0 && dis[i] < dis[flag]) flag = i;
		}
		vis[flag] = 1;
		ans = max(ans, dis[flag]);
		if (flag == k + 1) break;
		for (int i = 1; i <= k; i++) {
			dis[i] = min(dis[i], Dist(i, flag));
		}
		dis[k + 1] = min(dis[k + 1], y[flag]);
	} 
	printf ("%.9lf", ans / 2);
	return 0;
}