0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

順列組合せライブラリ

Last updated at Posted at 2024-05-26

この記事のオリジナル は,2023年2月28日に公開されました.

競技プログラミング用の,順列組合せ (重複有り無し) を生成する自作 C++ ライブラリ Perm の使用法です.ソースコードはここ にあります.

struct

4つの struct がある.名前がおかしいのは歴史的理由による.

  • IntPerm 順列
  • IntComb 組合せ
  • IntDupPerm 重複順列
  • IntDupComb 重複組合せ

constructor

IntPerm ip(m, n);
IntComp ic(m, n);
IntDupPerm idp(m, n);
IntDupComb idc(m, n);

これらはいずれも,$[0, m)$ の数からなる長さ $n$ のリストを生成する.

このライブラリでは,「順列」と「組合せ」の違いは,後者は昇順にソートされている,ということである.

IntPerm

$[0, m)$ からなる長さ $n$ のリストで,同じ数がたかだか1回しか現れないものを列挙する.

たとえば ip(4, 2) は,次を生成する:

[0,1], [0,2], [0,3], [0,4], [1,0], [1,1], [1,2], [1,3], [2,0], [2,1], [2,2], [2,3], [3,0], [3,1], [3,2], [3,3]

IntComb

$[0, m)$ からなる長さ $n$ のリストで,同じ数がたかだか1回しか現れず,昇順ソートされているものを列挙する.

たとえば,ic(4, 2) は,次を生成する:

[0,1], [0,2], [0,3], [0,4], [1,2], [1,3], [2,3]

IntDupPerm

$[0, m)$ からなる長さ $n$ のリストを列挙する.

たとえば idp(4, 2) は,次を生成する:

[0,0], [0,1], [0,2], [0,3], [1,0], [1,1], [1,2], [1,3], [2,0], [2,1], [2,2], [2,3], [3,0], [3,1], [3,2], [3,3]

IntDupComb

$[0, m)$ からなる長さ $n$ のリストで,昇順ソートされているものを列挙する.

たとえば idc(4, 2) は,次を生成する:

[0,0], [0,1], [0,2], [0,3], [1,1], [1,2], [1,3], [2,2], [2,3], [3,3]

生成

obj.get() が true を返す間,新しいリストが生成される.リストの i 番目の要素は,obj.at() である.

while (ip.get()) {
  for (int i = 0; i < 2; i++) cout << ip.at(i) << " ";
}

注意1

obj.get() が false を返すときには,内部状態は初期値に戻るので,そのまま次のラウンドを実行することができる.

注意2

  • $n \geq 0, r \geq 0$ でないときには,何も生成しない.
  • IntPerm と IntComb は,$r \leq n$ でないときには,何も生成しない.
  • IntDupPerm と IntDupComb は,$n = r = 0$ のときに,何も生成しないのでは なく,空リスト [] を生成する.これは,ことによると適切でないかもしれない.($0^0 = 1$ になるし,$H(n, r) \neq C(n+r-1, r)$ になるから)
  • $n = 0$ かつ $r \neq 0$ の場合には,何も生成しない.

デバッグ用

const vector<int>& obj.vec_view(); でベクトルに変換できる.

忘れやすい利用シーン

ボールと仕切りの重複組合せ

区別されない $a$ 個のボールを 区別される $b$ 個の箱に入れる方法は,IntDupComb(b, a) が列挙するリストと対応付けられる.リスト $[x_1, ..., x_a]$ は,ボール $1$ が箱 $x_1$に,ボール $2$ が箱 $x_2$に,..., ボール $a$ が箱 $x_a$ に入っていることを意味している.(ボールを区別しないことは,入る箱を昇順にして良いことと対応している.) したがって,各箱に入っているボールの数は,次のように求められる.

IntDupComb idc(b, a);
while (idc.next()) {
  vector<ll> numBalls(b);
  REP(i, 0, a) numBalls[idc.at(i)]++;
  //  箱 j にはボールが numBalls[j] 個入っている
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?