challenge 「組合せ型の最小完全ハッシュ関数」の逆関数

まずは最小完全ハッシュ関数の作り方の後半部分をご覧ください。

「組み合わせ型の最小完全ハッシュ関数」とは 下のような「n個の値のうちm個が1で残りが0であるようなデータ」と整数とを対応づける関数です。下の例ではn=5でm=2になっています。 (「0以上n未満の整数から重複しないm個を選んだ組み合わせ」もデータとしては同じです)

>>> for xs in make_perm(5, 2):
	print xs, "=>", hash(xs, 5, 2)

	
[1, 1, 0, 0, 0] => 9
[1, 0, 1, 0, 0] => 8
[1, 0, 0, 1, 0] => 7
[1, 0, 0, 0, 1] => 6
[0, 1, 1, 0, 0] => 5
[0, 1, 0, 1, 0] => 4
[0, 1, 0, 0, 1] => 3
[0, 0, 1, 1, 0] => 2
[0, 0, 1, 0, 1] => 1
[0, 0, 0, 1, 1] => 0

「ハッシュ関数」というとデータが文字列であるものを連想しやすいですが、 ここで扱う対象データは文字列ではありません。(ちなみに文字列のハッシュ関数は、異なる文字列が同じハッシュ値になることがあるので「完全」ではありません。)

さて、ここからが本題です。 組み合わせのデータを与えると整数を返すのがこのハッシュ関数でした。 この逆の関数、「整数xを与えると、hash(data) == xになるような組み合わせのデータdataを返す関数」を作ってください。

このお題はshuyoさんの提案を元に作成しました。ありがとうございました。

Posted feedbacks - Prolog

hashは問題のハッシュ関数そのままの実装です。

?- hash(5, 2, [0, 1, 0, 1, 0], X).
X = 4

Prologのパターンマッチとバックトラックにより
逆関数としても使えます。

?- hash(5, 2, L, 4).
L = [0, 1, 0, 1, 0]

これはこれで面白いのですが
結局のところ順列を作りつつ調べていくので
n, mが大きくなると使い物になりません。

その点unhashは双方向ではありませんが
combを考えなければ計算量は線形です。

あと、combは一応メモ化してますが、
たぶん計算方法が良くないです。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
%%	comb(+N, +K, ?C)

:- dynamic comb/3.

comb(_, 0, 1) :- !.
comb(N, K, X) :-
	N0 is N - 1,
	K0 is K - 1,
	comb(N0, K0, X0),
	X is X0 * N / K,
	asserta(comb(N, K, X) :- !).

%%	hash(+N, +M, ?BitList, ?Hash)

hash(0, 0, [], 0) :- !.
hash(N, M, [1|Bs], H) :-
	succ(M0, M),
	succ(N0, N),
	comb(N0, M, C),
	hash(N0, M0, Bs, H0),
	H is C + H0.
hash(N, M, [0|Bs], H) :-
	succ(N0, N),
	hash(N0, M, Bs, H).

%%	unhash(+N, +M, +Hash, ?BitList)

unhash(0, 0, _, []) :- !.
unhash(N, M, H, [B|Bs]) :-
	N0 is N - 1,
	(   N > 0,
	    comb(N0, M, C),
	    H >= C
	->  B = 1,
	    H0 is H - C,
	    M0 is M - 1,
	    unhash(N0, M0, H0, Bs)
	;   B = 0,
	    unhash(N0, M, H, Bs)
	).

Index

Feed

Other

Link

Pathtraq

loading...