C ++
 Computer >> コンピューター >  >> プログラミング >> C ++

C++でのビットマスキングと動的計画法


最初に、ビットマスキングと動的計画法について学び、次に、実装に関連するクエリを解決する、それに関連する問題を解決します。

ビットマスク マスクとも呼ばれます コレクションのサブセットをエンコードするNビットのシーケンスです。マスクの要素は、設定することも設定しないこともできます(つまり、0または1)。これは、ビットマスクで選択された要素の可用性を示します。たとえば、マスクのi番目のビットが設定されている場合、要素iはサブセットで使用できます。 N要素セットの場合、2 N が存在する可能性があります サブセットに対応するそれぞれをマスクします。

したがって、問題を解決するために、マスクから開始します。つまり、サブセットがそれに値を割り当て、前のマスクの値を使用してさらにマスクの値を見つけます。これを使用して、最終的にメインセットの値を計算できるようになります。

マスクの最適解を計算するために、考えられるすべての方法で1つの要素を削除し、すべての値を計算して、最終的な解に貢献します。

動的計画法

動的計画法は、サブ問題を解決し、それらのソリューションを他の重複するサブ問題で使用できるように保存する最適化手法です。

では、ビットマスキングと動的計画法を使用して解決する問題を見てみましょう。

問題

1から50までの数字の50のキャップがあります。N人はコレクションにこれらのキャップのいくつかを持っています。ある日、彼ら全員がパーティーに帽子をかぶる。しかし、すべてがユニークに見える必要があるので、彼らはそれぞれ異なる番号のキャップを着用することにしました。コレクションには、n人の人数とキャップ番号が与えられます。私たちの仕事は、誰もがユニークに見えるように、キャップを着用できる方法の総数を見つけることです。

この問題では、最初の行に値n、つまり人数が含まれています。次のn行にはコレクションが含まれています。

入力

3
4 45 10
25
45 10

出力

4

説明

考えられるすべての方法は、(4、25、45)、(4、25、10)、(45、25、10)、(10、25、45)です。

ウェイの数が多くなる可能性があるため、出力は1000000007の形式にする必要があります。

この問題を解決するための簡単な解決策は、キャップを使用している人々のすべての可能な組み合わせを見つけることです。最初のセットから開始して、残りのセットを繰り返します。ただし、このソリューションは最適化されていません。

より良い解決策は、10人用にサイズ210のマスクを作成することにより、ビットマスキングとDPを使用することです。そして、サイズ51のキャップのベクトル。次に、さまざまな方法で繰り返します。

ソリューションの実装を示すプログラム

#include<bits/stdc++.h>
using namespace std;
vector<int> caps[101];
int dp[1025][101];
int allmask;
long long int uniqueCaps(int mask, int i) {
   if (mask == allmask) return 1;
   if (i > 100) return 0;
   if (dp[mask][i] != -1) return dp[mask][i];
   long long int ways = uniqueCaps(mask, i+1);
   int size = caps[i].size();
   for (int j = 0; j < size; j++) {
      if (mask & (1 << caps[i][j])) continue;
         else ways += uniqueCaps(mask | (1 << caps[i][j]), i+1);
         ways %= (1000000007);
      }
      return dp[mask][i] = ways;
   }
int main() {
   int n = 3;
   // Collection of person 1
   caps[4].push_back(0);
   caps[45].push_back(0);
   caps[10].push_back(0);
   // Collection of person 2
   caps[25].push_back(1);
   // Collection of person 3
   caps[45].push_back(2);
   caps[10].push_back(2);
   allmask = (1 << n) - 1;
   memset(dp, -1, sizeof dp);
   cout<<"The number of ways the person can wear unique cap in party is:\t"<<uniqueCaps(0, 1);
   return 0;
}

出力

The number of ways the person can wear unique cap in party is: 4

  1. 動的計画法を使用して数値の階乗を見つけるC++プログラム

    正の整数nの階乗は、1 * 2 * 3 *...nに等しくなります。負の数の階乗は存在しません。ここでは、動的計画法を使用して特定の入力の階乗を見つけるためのC++プログラムが提供されています。 アルゴリズム Begin    fact(int n):       Read the number n       Initialize       i = 1, result[1000] = {0}       result[0] = 1   &nb

  2. Javaでの暗記(1D、2D、3D)動的計画法

    暗記は動的計画法に基づく手法であり、提供された入力の結果を記録することにより、メソッドが同じ入力セットに対して複数回実行されないようにすることで、再帰的アルゴリズムのパフォーマンスを向上させるために使用されます(配列)。再帰的方法のトップダウンアプローチを実装することにより、暗記を実現できます。 基本的なフィボナッチの例を参考にして、このシナリオを理解しましょう 1-D暗記 非定数パラメーターが1つだけ(1つのパラメーターだけが値を変更する)の再帰的アルゴリズムを検討するため、この方法は1次元記憶と呼ばれます。次のコードは、フィボナッチ数列のN番目(Nまでのすべての項)を見つけるためのもの