4

しばらくの間対処できない興味深い問題があります。N 個の手紙とそれに対応する N 個の封筒があります。これは、すべての手紙と封筒が (同じ順列で) アドレス指定されていることを意味します。タスクは、定点を持たない文字の可能な順列の数を見つけることです。各文字は、この文字とは異なる宛名の封筒に入っています。手紙 (および封筒) が何らかの N 順列によってアドレス指定されている場合、問題は非常に簡単です。次に、N-derangements ( http://en.wikipedia.org/wiki/Derangement )の数を見つけるだけです。

しかし、この問題は一般的にはもっと興味深いものになる可能性があります。数字 N と N の数字が与えられます。i 番目の数字は、i 番目の手紙 (および封筒) の住所を示します。最初の数字は 0 です (したがって、 [0,...,N-1] で番号付けされた手紙と封筒があります)。それでは、いくつの混乱がありますか?たとえば、次のように与えられます。

 5 
 1 1 2 2 3

それぞれの手紙が対応する封筒に入っていない状況は 4 つしかないため、答えは 4 です。

2 2 1 3 1
2 2 3 1 1 
2 3 1 1 2
3 2 1 1 2

(そのため、同じ住所の手紙を区別しません)。

為に:

6
0 0 0 1 1 1

答えは 1 です。理由: 1 1 1 0 0 0 が唯一の方法です。

私はほとんど忘れていました.. 1<=N<=15 で十分です。

それを非常に迅速にカウントする方法と、その方法はあるのでしょうか。

アルゴリズムでどのようにアプローチすればよいですか?

4

2 に答える 2

2

最初の試行では、単純な動的計画法の問題として扱ってください。

したがって、封筒のリストの各位置について、左から右に作業し、残せる可能性のある文字の各セットについて、そのポイントに到達する方法の数を計算します. 先に進むのは簡単です。セットを取得するだけで、そこに到達する方法がいくつあるかがわかります。次に、次の封筒に入れることができる文字ごとに、結果のセットの合計を方法の数だけ増やしますその点に到達するために。封筒のリストの最後に到達すると、残りの文字を 0 にする方法がいくつあるかがわかります。これが答えです。

2 番目の例では、次のように進行する可能性があります。

Step 0: next envelope 1
  {1: 2, 2: 2, 3: 1}: 1
    -> {1: 2, 2: 1, 3: 1}
    -> {1: 2, 2: 2}

Step 1: next envelope 1
  {1: 2, 2: 1, 3: 1}: 1
    -> {1: 2, 2: 1}
    -> {1: 2, 3: 1}
  {1: 2, 2: 2}: 1
    -> {1: 2, 2: 1}

Step 2: next envelope 2
  {1: 2, 2: 1}: 2
    -> {1: 1, 2: 1}
  {1: 2, 3: 1}: 1
    -> {1: 1, 3: 1}
    -> {1: 2}

Step 3: next envelope 2
  {1: 1, 2: 1}: 2
    -> {2: 1}
  {1: 1, 3: 1}: 1
    -> {1: 1}
    -> {3: 1}
  {1: 2}: 1
    -> {1: 1}

Step 4: next envelope 3
  {2: 1}: 2
    -> {}
  {1: 1}: 2
    -> {}
  {3: 1}: 1
    // Dead end.

Step 5:
  {}: 4

これは機能し、要求した計算範囲に到達します。15 の場合、2^15 = 32768 の可能なサブセットを追跡することができ、これは非常に実行可能です。ただし、20 前後でメモリが不足し始めます。

これを改善できますか?答えは、できるということです。私たちのエネルギーの大部分は、たとえば、これまでに 8 とラベル付けされた封筒と 9 とラベル付けされた封筒を使用したかどうかを思い出すことに費やされます。しかし、私たちはそれを気にしません。終了する方法がいくつあるかを決定するのは、封筒 8 を使用したか 9 を使用したかではなく、パターンです。x 封筒と y 通の手紙が残っているラベルはいくつありますか。どのラベルがどれであるかではなく、いくつあるかだけです。

したがって、その情報だけを追跡すると、各ステップで、封筒の残りが最も多いラベルの付いた封筒を取得できます。同点の場合は、残りの文字数が最も少ない封筒を選択しますネクタイ、どちらを取得するかは本当に気にしません)。前と同じように計算を行いますが、中間状態ははるかに少なくなります。(あなたが持っている封筒をそのまま並べて巻き上げるわけではありません。しかし、封筒を使って最終的な手紙を安定してソートすると、上記のリストが返されます。)

封筒や手紙が残っているラベル[x y]: zがあるという意味で表記してみましょう。そして、そのようなラベルのリストがあります。次に、の例は次のように表すことができます。トランジションでは、ラベルの 1 つを取得して、もう一方のラベルの文字を使用するか ( への遷移を与える)、ラベルの 1 つを取得し、ラベルの文字を使用します(への移行)。zxy1 1 2 2 3{[2 2]: 2, [1 1]: 1}[2 2]{[2 1]: 1, [1 2]: 1, [1 1]: 1}[2 2][1 1]{[2 2]: 1, [1 2]: 1, [1 0]: 1}

計算を実行しましょう。状態、そこに到達する方法の数、およびあなたが行う遷移をリストします。

Step 1:
  {[2 2]: 2, [1 1]: 1}: 1
    -> 1 * {[2 1]: 1, [1 2]: 1, [1 1]: 1}
    -> 1 * {[2 2]: 1, [1 2]: 1, [1 0]: 1}

Step 2:
  {[2 1]: 1, [1 2]: 1, [1 1]: 1}: 1
    -> 1 * {[1 1]: 3}
    -> 1 * {[1 1]: 1, [1 2]: 1, [1 0]: 1}
  {[2 2]: 1, [1 2]: 1, [1 0]: 1}: 1
    -> 1 * {[1 2]: 1, [1 1]: 1, [1 0]: 1}

Step 3:
  {[1 1]: 3}: 1
       // This is 2x because once the label is chosen, there are 2 letters to use.
    -> 2 * {[0 1]: 1, [1 0]: 1, [1 1]: 1}
  {[1 1]: 1, [1 2]: 1, [1 0]: 1}: 2
    -> 1 * {[1 0]: 1, [1 2]: 1, [0 0]: 1}
    -> 1 * {[1 1]: 2, [0 0]: 1}
  {[1 2]: 1, [1 1]: 1, [1 0]: 1}: 1
    -> 1 * {[1 1]: 2, [0 0]: 1}
    -> 1 * {[1 2]: 1, [1 0]: 1, [0 0]: 1}

Step 4:
  {[0 1]: 1, [1 0]: 1, [1 1]: 1}: 2
    -> 1 * {[1 1]: 1, [0 0]: 2}
    -> 1 * {[1 0]: 1, [0 1]: 1, [0 0]: 1}
  {[1 0]: 1, [1 2]: 1, [0 0]: 1}: 2
    -> 1 * {[1 1]: 1, [0 0]: 2}
  {[1 1]: 2, [0 0]: 1}: 2
    -> 1 * {[1 0]: 1, [0 1]: 1, [0 0]: 1}

Step 5:
  {[1 1]: 1, [0 0]: 2}: 4
    // dead end
  {[1 0]: 1, [0 1]: 1, [0 0]: 1}: 4
    -> 1 * {[0 0]: 3}

なので答えは4です。

これは途方もない量の作業のように思えるかもしれません - 列挙するよりもはるかに多くの作業です。そしてそうだった!

ただし、スケーリングします。100 通の手紙と封筒で試してみると、すぐに実行されるはずです。

于 2012-06-29T21:43:48.130 に答える
0

15 の「通常の」順列では、力ずくで 1.3*10^9 回の試行が必要になりますが、同じキーを使用すると、残っている順列がはるかに少なくなります。

あなたの例を使用してみましょう: 1 1 2 2 3 の 5 枚のカード

順列配列を設定する

5 4 3 2 1

数値のように右から左に減らして、それを繰り返す準備をします。順列ではないすべての組み合わせを無視します。

5 4 3 2 1 無視

5 4 3 2 0 無視

5 4 3 1 5 無視

...

5 4 3 1 2 わかりました

議論の余地はありますが、これはより優れた順列アルゴリズムで大幅に改善される可能性がありますが、これは簡単ではありません。よく考えなければなりません。

次のステップは、比較を生成することです。順列配列は順列を選択します。

5 4 3 1 2 は 3 2 2 1 1 を意味します

これは混乱をテストします。比較を大幅に高速化する 1 つのことは、無効な組み合わせをスキップできることです。

最初の 5 が間違ったアイテムを選択した場合、5 つの XXXX 順列をすべてスキップして、4 5 3 2 1 に進むことができます。

混乱を見つけるたびに、カウンターを増やします。終わり。

于 2012-06-29T20:22:51.943 に答える