AtCoder

ABC270 F問題(Transportation)を解く

AtCoder_ABC270_F

AtCoder が提供しているABC(AtCoder Beginner Contest)270 のF問題をC++で解いてみました。ABC270は、2022年9月24日21:00に実施されました。

AtCoder の紹介はこちらに、プログラミングの方針はこちらに記事があります。

F問題 Transportation(Difficulty : 1834)

問題はリンク先をご覧ください。

ABC270 F問題 Transportation

空港と港のそれぞれの有無で4通りの最小全域木を作ります。AtCoder Problems による Difficulty は、1834 でした。

解答案

仮に空港も港もないとすると、道路だけを使った最小全域木の問題となります。クラスカル法を用いるとコストが小さい方から、UnionFind で統合していくだけです。

空港を作って飛行機を使う場合は、空を仮の頂点として設定すると同じことができます。港を作って船を使う場合は、海を仮の頂点として設定すると同じことができます。空港と港の有無で4つの最小全域木が構築できますが、そのコストの最小値が解答となります。

C++ プログラム例(ABC270F)

空港と港の有無を0から3までのビット表現でループさせます(bit全探索)。それぞれの場合で、頂点数(v_size)と辺のコスト(cost)を設定します(29ー46行目)。

  • 空港を作る場合、頂点N+1を空と考えます。
  • 港を作る場合、頂点N+2を海と考えます。

コストが小さい方から、UnionFind を使って頂点を統合していきます(48ー60行目)。統合した頂点数と頂点数が一致する場合に、最小値を更新します(63行目)。

以下が、C++プログラムとなります。

#include <bits/stdc++.h>
#include <atcoder/dsu>
using namespace std;
using namespace atcoder;

typedef long long int ll;
#define INF (1ULL << 60)

int main()
{
	int n, m;
	cin >> n >> m;
	vector<ll> x(n);
	for (int i = 0; i < n; ++i) {
		cin >> x[i];
	}
	vector<ll> y(n);
	for (int i = 0; i < n; ++i) {
		cin >> y[i];
	}
	vector<int> a(m), b(m);
	vector<ll> z(m);
	for (int i = 0; i < m; ++i) {
		cin >> a[i] >> b[i] >> z[i];
	}

	ll result = INF;
	for (int bit = 0; bit < 4; ++bit) {
		int v_size = n;
		vector<pair<ll, pair<int, int>>> cost;
		if ((bit & 1) != 0) {
			++v_size;
			for (int i = 0; i < n; ++i) {
				cost.push_back(make_pair(x[i], make_pair(i + 1, n + 1)));
			}
		}
		if ((bit & 2) != 0) {
			++v_size;
			for (int i = 0; i < n; ++i) {
				cost.push_back(make_pair(y[i], make_pair(i + 1, n + 2)));
			}
		}
		for (int i = 0; i < m; ++i) {
			cost.push_back(make_pair(z[i], make_pair(a[i], b[i])));
		}
		sort(cost.begin(), cost.end());

		dsu uf(n + 3);
		ll this_result = 0;
		ll this_size = 1;
		for (int i = 0; i < cost.size(); ++i) {
			ll c = cost[i].first;
			int n1 = cost[i].second.first;
			int n2 = cost[i].second.second;
			if (!uf.same(n1, n2)) {
				uf.merge(n1, n2);
				this_result += c;
				++this_size;
			}
		}

		if (this_size == v_size) {
			result = min(result, this_result);
		}
	}

	cout << result << endl;

	return 0;
}

AC(Accepted=正しいプログラム)と判定されました。

Python は、標準ライブラリで UnionFind が用意されていないため、プログラムの紹介を省略します。

最後に

ABC270のコンテスト時は、AとB問題の2問しか解けませんでした。F問題は問題を読むことさえできませんでした。

この問題は、青Difficultyでした。以下の要素を組み合わせています。

このレベルの問題が、本番コンテストで解ければと思います。

引き続き ABC の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA