AtCoder

ABC328 F問題(Good Set Query)を解く

AtCoder_ABC328_F

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

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

F問題 Good Set Query(Difficulty : 1477)

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

ABC328 F問題 Good Set Query

重み付きUnionFindを使って解くことができました。AtCoder Problems による Difficulty は 1477 でした。

解答案

前日に、重み付きUnionFindの紹介をしました(記事)。このライブラリをそのまま使うだけで、この問題を解くことができます。

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

クラス Weighted_UnionFind は、整備したコードをそのまま使いました(6ー77行目)。

(ai, bi, di) を加えると良い集合にならない条件をまとめます。

  • ai と bi が連結していることが前提となります。逆に ai と bi が連結していなければ連結して良い集合となります。
  • 上記を満たして、bi と ai の距離が di ではない。

良い集合となる添え字を出力します。以下が、C++プログラムとなります。

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

typedef long long int ll;

class Weighted_UnionFind {
private:
	int n;
	std::vector<int> par;
	std::vector<ll> diff_weight;

public:
	Weighted_UnionFind(int _n) {
		n = _n;
		par.resize(n, -1);
		diff_weight.resize(n, 0);
	}

	int leader(int x) {
		if (par[x] < 0) {
			return x;
		} else {
			int r = leader(par[x]);
			diff_weight[x] += diff_weight[par[x]];
			return par[x] = r;
		}
	}

	ll weight(int x) {
		leader(x);
		return diff_weight[x];
	}

	ll diff(int x, int y) {
		return weight(y) - weight(x);
	}

	void merge(int x, int y, ll w) {
		w += weight(x);
		w -= weight(y);
		x = leader(x);
		y = leader(y);
		if (x != y) {
			if (-par[x] < -par[y]) {
				std::swap(x, y);
				w = -w;
			}
			par[x] += par[y];
			par[y] = x;
			diff_weight[y] = w;
		}
	}

	bool same(int x, int y) {
		return leader(x) == leader(y);
	}

	int size(int x) {
		return -par[leader(x)];
	}

	std::vector<std::vector<int>> groups() {
		std::vector<std::vector<int>> member(n);
		for (int i = 0; i < n; ++i) {
			member[leader(i)].push_back(i);
		}

		std::vector<std::vector<int>> result;
		for (int i = 0; i < n; ++i) {
			if (!member[i].empty()) {
				result.push_back(member[i]);
			}
		}

		return result;
	}
};

int main()
{
	int n, q;
	cin >> n >> q;
	Weighted_UnionFind uf(n + 1);
	vector<int> result;
	for (int i = 0; i < q; ++i) {
		int a, b;
		ll d;
		cin >> a >> b >> d;
		if (uf.same(a, b)) {
			if (uf.diff(b, a) != d) {
				continue;
			}
		} else {
			uf.merge(b, a, d);
		}
		result.push_back(i + 1);
	}

	for (int i = 0; i < result.size(); ++i) {
		cout << result[i] << " \n"[i == result.size() - 1];
	}

	return 0;
}

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

Python の重み付きUnionFindについて

Python は、重み付きUnionFind を標準ライブラリとしては用意していません。このブログの Python プログラムは、なるべく言語標準のライブラリで実装したいと考えています。このような事情で、この記事では、Python に移植したプログラムの紹介を省略します。

最後に

コンテストでは解くことができませんでした。公式解説を参考にして、先にライブラリを整備しました。知っていれば解ける問題だと感じました。焦らず自分が使える道具を増やしていきます。

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

COMMENT

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

CAPTCHA