boost::disjoint_sets

トップページ > アルゴリズム >

abstract

必要なヘッダ
<boost/pending/disjoint_sets.hpp>
出来ること
同値類の分類アルゴリズム
リファレンス
en / jp

sample

サンプルの動作確認バージョン [GCC4.4/1.41.0] [VC9/1.41.0]

Rubyで同値関係を求めるパズル」という記事の例をBoost.Disjoint_setsで書いてみました。

簡単のため「xxx yyy」という空白区切り形式のデータを標準入力からたくさん受け取り、 等しいもの同士をグルーピングして、「xxxx yyyy zzzz ...」のような形式で出力しています。

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <iterator>
#include <algorithm>
#include <boost/pending/disjoint_sets.hpp>
using namespace std;

class Solver
{
public:
	void solve( const vector< pair<string,string> >& input )
	{
		// 入力された名前全てに一意なIDを振る
		for(int i=0; i!=input.size(); ++i)
			id_of(input[i].first), id_of(input[i].second);

		// size()個の要素の同値類分解処理
		boost::disjoint_sets_with_storage<> s( size() );
		for(int i=0; i!=input.size(); ++i)
			// 同じもの同志をunion_setで結合
			s.union_set(id_of(input[i].first), id_of(input[i].second)); 

		map< int, vector<string> > equiv;
		for(int id=0; id<size(); ++id)
		{
			// 各要素の同値類の代表元rootを取り出して、それ毎にまとめる
			int root = s.find_set(id);
			equiv[root].push_back( InverseID[id] );
		}

		// 表示
		for(map< int, vector<string> >::iterator it=equiv.begin(), ed=equiv.end();
		    it!=ed; ++it)
		{
			copy( it->second.begin(), it->second.end(),
			      ostream_iterator<string>(cout, " ") );
			cout << endl;
		}
	}

private:
	// IDを振る処理
	int id_of( const string& name )
	{
		if( ID.count(name)==0 )
		{
			ID[name] = size();
			InverseID.push_back(name);
		}
		return ID[name];
	}
	int size() const
	{
		return InverseID.size();
	}
	map<string, int> ID;
	vector<string>   InverseID;
};

int main()
{
	// 入力
	vector< pair<string,string> > input;
	for(string x,y; cin>>x>>y; )
		input.push_back( make_pair(x,y) );
	Solver().solve(input);
}

入力例

少女 リズ
少年 ペタ
楽天家 ゲルト
老人 モーリッツ
... (以下略) ...

出力例

少女 リズ リーザ リー
少年 ペタ ペーター ペー太
楽天家 ゲルト
老人 モーリッツ 翁
... (以下略) ...

etc

とまあ、こんな雰囲気で、union_set と find_set メソッドを提供してくれるクラスです。 実装されているのが自然数集合のunionとfindなので、上の例では、文字列をintに手で変換しています。 例では disjoint_sets の完全に外側で int と文字列を変換していますが、 PropertyMap 形式で変換オブジェクトを disjoint_sets に渡すことで、変換操作自体は disjoint_sets に任せることも可能です。 また、最初には全部の要素数がわかっていないような場合、boost::disjoint_sets_with_storage<> ではなく boost::disjoint_sets<> が使えます。

ところで、公式のライブラリ一覧に載ってはいるものの、 置かれているフォルダが boost/pending/ なのはどういうことなんでしょうか。謎です。

presented by k.inaba (kiki .a.t. kmonos.net) under CC0