AtCoder

ABC352 E問題(Clique Connect)を解く

AtCoder_ABC352_E

AtCoder が提供しているABC(AtCoder Beginner Contest)352 のE問題をC++で解いてみました。ABC352は、2024年5月4日21:00に実施されました。

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

E問題 Clique Connect(Difficulty : 1030)

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

ABC352 E問題 Clique Connect

重みが少ない辺から統合していきますが、一工夫必要です。AtCoder Problems による Difficulty は 1030 でした。

解答案

最小全域木を求める問題です。なお、最小全域木については、「典型アルゴリズム問題集」のF問題で紹介しています。

重みが少ない辺から統合していきます。ただし、設定されている辺の数が多く、すべてを統合していっては時間が足らなくなります。

$K_i$ 頂点からなる頂点の部分集合 $S_i$ 内には、$K_i \times (K_i \; – \; 1) / 2$ 個の辺があります。これらの辺をすべて統合する必要はありません。$K_i – 1$個の辺を統合すれば、部分集合 $S_i$ 内は連結します。以下の制約があり、時間的にも間に合います。

$$\sum^{M}_{i=1} K_i \leqq 4 \times 10^5$$

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

$S_i$ 内の辺のコスト $C_i$ とインデックスをまとめてソートします。重みが小さい方から、辺を統合します。統合には、ACL の UnionFind を使いました。それぞれの $S_i$ の辺は、$K_i – 1$ 本だけ統合しています(32行目のfor文)。

頂点1に統合されている頂点数を調べて、それが $N$ に一致していなければ、全体が連結していません(40行目のif文)。

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

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

typedef long long int ll;

int main()
{
	int n, m;
	cin >> n >> m;
	vector<int> k(m);
	vector<ll> c(m);
	vector<vector<int>> a(m);
	vector<pair<int, int>> order_c; 
	for (int i = 0; i < m; ++i) {
		cin >> k[i] >> c[i];
		for (int j = 0; j < k[i]; ++j) {
			int t;
			cin >> t;
			a[i].push_back(t);
		}
		order_c.push_back(make_pair(c[i], i));
	}
	sort(order_c.begin(), order_c.end());

	ll result = 0;
	dsu uf(n + 1);
	for (int i = 0; i < m; ++i) {
		ll cost = order_c[i].first;
		int index = order_c[i].second;
		for (int j = 0; j < k[index] - 1; ++j) {
			if (!uf.same(a[index][j], a[index][j + 1])) {
				uf.merge(a[index][j], a[index][j + 1]);
				result += cost;
			}
		}
	}

	if (uf.size(1) != n) {
		result = -1;
	}
	cout << result << endl;

	return 0;
}

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

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

最後に

E問題が解けることは珍しいのですが、最小全域木については相性が良かったのか解くことができました。

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

COMMENT

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

CAPTCHA