3

私は最近CNSFNSについて学びました。それらは私にはとてもエレガントに見えるので、これらの手法を使用して組み合わせと順列を生成する方法を試して実装することにしました。n choose kの組み合わせを CSN ランクに、またはその逆に変換する方法を終了しましたが、 n choose k (一意の) 順列で同じことをしようとして頭を壁にぶつけています。

@Joshuaのおかげで、ランキング解除(FNS から順列) メソッドが機能しました。

function Pr_Unrank($n, $k, $rank) { // rank starts at 1
    if ($n >= $k) {
        if (($rank > 0) && ($rank <= Pr($n, $k))) {
            $rank--;
            $result = array();
            $factoriadic = array();

            for ($i = 1; $i <= ($n - $k); ++$i) {
                $rank *= $i;
            }

            for ($j = 1; $j <= $n; ++$j) {
                $factoriadic[$n - $j] = ($rank % $j) + 1; $rank /= $j;
            }

            for ($i = $n - 1; $i >= 0; --$i) {
                $result[$i] = $factoriadic[$i];

                for ($j = $i + 1; $j < $n; ++$j) {
                    if ($result[$j] >= $result[$i]) {
                        ++$result[$j];
                    }
                }
            }

            return array_reverse(array_slice($result, 0 - $k));
        }
    }

    return false;
}

これは、ランキング(FNSへの順列)メソッドでの私の現在の試みです:

function Pr_Rank($n, $k, $permutation) {
    if ($n >= $k) {
        $result = range(1, $n);
        $factoriadic = array();

        foreach ($permutation as $key => $value) {
            $factoriadic[$k - $key - 1] = array_search($value, $result);
            array_splice($result, $factoriadic[$k - $key - 1], 1);
        }

        $result = 1;

        foreach (array_filter($factoriadic) as $key => $value) {
            $result += F($key) * $value;
        }

        return $result;
    }

    return false;
}

そして、これらは私が使用しているヘルパー関数です:

function F($n) { // Factorial
    return array_product(range($n, 1));
}

function Pr($n, $k) { // Permutations (without Repetitions)
    return array_product(range($n - $k + 1, $n));
}

問題は、(Pr_Rank()n = k demo )場合にのみメソッドが正しいランクを返すことです。

var_dump(Pr_Rank(5, 2, Pr_Unrank(5, 2, 10))); // 3, should be 10
var_dump(Pr_Rank(5, 3, Pr_Unrank(5, 3, 10))); // 4, should be 10
var_dump(Pr_Rank(5, 5, Pr_Unrank(5, 5, 10))); // 10, it's correct

上記でリンクしたウィキペディアの記事とこの MSDN の記事を使用して自分自身を導きました。どちらも k サイズのサブセットを検討していませんが、そのようなロジックがどのように見えるかは完全にわかりません...

また、グーグルで既存の質問/回答を検索してみましたが、関連するものはまだありません。

4

1 に答える 1

3

ぐっすり眠り、ペンと紙で少し助けた後、私はそれを理解しました. 誰かが興味を持っている場合:


たとえば、42 番目の5 選択 3順列は ですが、 が呼び出される場所4-2-5を見ると、実際の順列 (辞書式の順序で) が実際には であることがわかります。最後の 2 つの要素は破棄されるため、最終的には要素。Pr_Unrank()array_slice()4-2-5[-1-3]k

3-1-2[-0-0]これは、階乗 ( )の 10 進数表現を計算するために非常に重要です。

  • 4-2-5= (2! * 3) + (1! * 1) + (0! * 2)=9
  • 4-2-5-1-3= (4! * 3) + (3! * 1) + (2! * 2) + (1! * 0) + (0! * 0)=82

それでも、82正解ではありません。それを取得するには、次の結果で割る必要があります。

  • Pr(5, 5) / Pr(5, 3)(=) (5 - 3)!= 120 / 60=2

そう82 / 2です41、私がする必要があるのは1、1から始まるランキングを取得するために追加することだけです.


Array // 5 choose 3 permutations
(
    [1] => 1-2-3
    [2] => 1-2-4
    [3] => 1-2-5
    [4] => 1-3-2
    [5] => 1-3-4
    [6] => 1-3-5
    [7] => 1-4-2
    [8] => 1-4-3
    [9] => 1-4-5
    [10] => 1-5-2
    [11] => 1-5-3
    [12] => 1-5-4
    [13] => 2-1-3
    [14] => 2-1-4
    [15] => 2-1-5
    [16] => 2-3-1
    [17] => 2-3-4
    [18] => 2-3-5
    [19] => 2-4-1
    [20] => 2-4-3
    [21] => 2-4-5
    [22] => 2-5-1
    [23] => 2-5-3
    [24] => 2-5-4
    [25] => 3-1-2
    [26] => 3-1-4
    [27] => 3-1-5
    [28] => 3-2-1
    [29] => 3-2-4
    [30] => 3-2-5
    [31] => 3-4-1
    [32] => 3-4-2
    [33] => 3-4-5
    [34] => 3-5-1
    [35] => 3-5-2
    [36] => 3-5-4
    [37] => 4-1-2
    [38] => 4-1-3
    [39] => 4-1-5
    [40] => 4-2-1
    [41] => 4-2-3
    [42] => 4-2-5
    [43] => 4-3-1
    [44] => 4-3-2
    [45] => 4-3-5
    [46] => 4-5-1
    [47] => 4-5-2
    [48] => 4-5-3
    [49] => 5-1-2
    [50] => 5-1-3
    [51] => 5-1-4
    [52] => 5-2-1
    [53] => 5-2-3
    [54] => 5-2-4
    [55] => 5-3-1
    [56] => 5-3-2
    [57] => 5-3-4
    [58] => 5-4-1
    [59] => 5-4-2
    [60] => 5-4-3
)
于 2012-06-23T07:29:27.620 に答える