Official

L - 発電所 / Power Station Editorial by sounansya


発電所を作る操作を仮想的に存在する発電所との間に電線を張る操作と捉えることで、この問題は \(N+1\) 個の都市と(仮想的な)発電所に \(N\) 本の電線を張り最小コストで連結にする問題に帰着させることができます。

そして、この問題はまさに最小全域木を求めることに等しく、プリム法やクラスカル法などを用いることでこの問題を高速に解くことができることが知られています。

以上を適切に実装することでこの問題に正答することができます。

実装例 (C++)

#include <atcoder/dsu>
#include <bits/stdc++.h>
using namespace std;
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int n;
	cin >> n;
	vector<double> x(n), y(n);
	for (int i = 0; i < n; i++)
		cin >> x[i] >> y[i];
	vector<double> p(n);
	for (int i = 0; i < n; i++)
		cin >> p[i];

	vector<tuple<int, int, double>> g;
	g.reserve(n * n + n);

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < i; j++) {
			double dx = x[i] - x[j];
			double dy = y[i] - y[j];
			g.push_back({i, j, sqrt(dx * dx + dy * dy)});
		}
	}
	for (int i = 0; i < n; i++)
		g.push_back({n, i, p[i]});

	sort(g.begin(), g.end(), [](auto &a, auto &b) { return get<2>(a) < get<2>(b); });

	atcoder::dsu d(n + 1);
	double ans = 0;

	for (auto [a, b, c] : g) {
		if (!d.same(a, b)) {
			d.merge(a, b);
			ans += c;
		}
	}
	cout << fixed << setprecision(20) << ans << "\n";
}

posted:
last update: