📜  计算选择N对不同颜色的糖果的方式(动态编程+位掩码)

📅  最后修改于: 2021-04-17 16:47:08             🧑  作者: Mango

给定一个代表红色和蓝色糖果数量的整数N和一个大小为N * N的矩阵mat [] [] ,其中mat [i] [j] = 1表示在i红色糖果和j糖果之间存在一对蓝色糖果,任务是找到选择N对糖果的方法,以使每对糖果包含不同颜色的独特糖果。

例子:

天真的方法:解决此问题的最简单方法是生成包含不同颜色的不同糖果的N对的所有可能排列。最后,打印获得的计数。

下面是上述方法的实现:

C++14
// C++14 program to implement
// the above approach
#include 
using namespace std;
 
// Function to count ways to select N distinct
// pairs of candies with different colours
int numOfWays(vector> a, int n,
                 int i, set &blue)
{
     
    // If n pairs are selected
    if (i == n)
        return 1;
 
    // Stores count of ways
    // to select the i-th pair
    int count = 0;
 
    // Iterate over the range [0, n]
    for(int j = 0; j < n; j++)
    {
         
        // If pair (i, j) is not included
        if (a[i][j] == 1 && blue.find(j) == blue.end())
        {
            blue.insert(j);
            count += numOfWays(a, n, i + 1, blue);
            blue.erase(j);
        }
    }
    return count;
}
 
// Driver Code
int main()
{
    int n = 3;
    vector> mat = { { 0, 1, 1 },
                                { 1, 0, 1 },
                                { 1, 1, 1 } };
    set mpp;
     
    cout << (numOfWays(mat, n, 0, mpp));
}
 
// This code is contributed by mohit kumar 29


Java
// Java program to implement
// the above approach
import java.io.*;
import java.lang.*;
import java.util.*;
 
class GFG{
 
// Function to count ways to select N distinct
// pairs of candies with different colours
static int numOfWays(int a[][], int n, int i,
                     HashSet blue)
{
     
    // If n pairs are selected
    if (i == n)
        return 1;
 
    // Stores count of ways
    // to select the i-th pair
    int count = 0;
 
    // Iterate over the range [0, n]
    for(int j = 0; j < n; j++)
    {
         
        // If pair (i, j) is not included
        if (a[i][j] == 1 && !blue.contains(j))
        {
            blue.add(j);
            count += numOfWays(a, n, i + 1, blue);
            blue.remove(j);
        }
    }
    return count;
}
 
// Driver Code
public static void main(String[] args)
{
    int n = 3;
    int mat[][] = { { 0, 1, 1 },
                    { 1, 0, 1 },
                    { 1, 1, 1 } };
    HashSet mpp = new HashSet<>();
 
    System.out.println((numOfWays(mat, n, 0, mpp)));
}
}
 
// This code is contributed by Kingash


Python3
# Python3 program to implement
# the above approach
 
 
# Function to count ways to select N distinct
# pairs of candies with different colours
def numOfWays(a, n, i = 0, blue = []):
 
    # If n pairs are selected
    if i == n:
        return 1
 
    # Stores count of ways
    # to select the i-th pair
    count = 0
 
    # Iterate over the range [0, n]
    for j in range(n):
 
        # If pair (i, j) is not included
        if mat[i][j] == 1 and j not in blue:
            count += numOfWays(mat, n, i + 1,
                                blue + [j])
                                 
    return count
 
# Driver Code
if __name__ == "__main__":
    n = 3
    mat = [ [0, 1, 1],
            [1, 0, 1],
            [1, 1, 1] ]
    print(numOfWays(mat, n))


C#
// C# program to implement
// the above approach
using System;
using System.Collections.Generic;
 
class GFG{
     
// Function to count ways to select N distinct
// pairs of candies with different colours
static int numOfWays(int[,] a, int n, int i,
                     HashSet blue)
{
     
    // If n pairs are selected
    if (i == n)
        return 1;
 
    // Stores count of ways
    // to select the i-th pair
    int count = 0;
 
    // Iterate over the range [0, n]
    for(int j = 0; j < n; j++)
    {
         
        // If pair (i, j) is not included
        if (a[i, j] == 1 && !blue.Contains(j))
        {
            blue.Add(j);
            count += numOfWays(a, n, i + 1, blue);
            blue.Remove(j);
        }
    }
    return count;
}
 
// Driver Code
public static void Main()
{
    int n = 3;
    int[,] mat = { { 0, 1, 1 },
                   { 1, 0, 1 },
                   { 1, 1, 1 } };
    HashSet mpp = new HashSet();
 
    Console.WriteLine((numOfWays(mat, n, 0, mpp)));
}
}
 
// This code is contributed by ukasp


Python3
# Python program to implement
# the above approach
  
  
# Function to count ways to select N distinct
# pairs of candies with different colors
def numOfWays(a, n):
 
 
    # dp[i][j]: Stores count of ways to make
    # pairs between i red candies and N blue candies
    dp = [[0]*((1 << n)+1) for _ in range(n + 1)]
 
    # If there is no red and blue candy,
    # the count of ways to make n pairs is 1
    dp[0][0] = 1
 
    # i: Stores count of red candy
    for i in range(n):
 
        # j generates a permutation of blue
        # candy of selected / not selected
        # as a binary number with n bits
        for j in range(1 << n):
 
            if dp[i][j] == 0:
                continue
    
            # Iterate over the range [0, n]   
            for k in range(n):
 
                # Create a mask with only
                # the k-th bit as set
                mask = 1 << k
                 
                # If Kth bit of mask is
                # unset  and mat[i][k] = 1
                if not(mask & j) and a[i][k]:
                    dp[i + 1][j | mask] += dp[i][j]
                     
         
                     
    # Return the dp states, where n red
    # and n blue candies are selected
    return dp[n][(1 << n)-1]
 
 
 
# Driver Code
if __name__ == "__main__":
    n = 3
    mat = [[0, 1, 1],
           [1, 0, 1],
           [1, 1, 1]]
    print(numOfWays(mat, n))


输出:
3

时间复杂度: O(N!)
辅助空间: O(1)

高效方法:可以使用带有位屏蔽的动态编程来优化上述方法。代替生成N个蓝色糖果的所有排列,对于每一个红色糖果,使用掩模,其中j比特掩码检查如果j蓝色糖果可用于在当前对或不选择。
解决该问题的递归关系如下:

请按照以下步骤解决问题:

  • 初始化一个2D数组,例如dp [] [] ,其中dp [i] [j]存储在i个红色糖果和N个蓝色糖果之间进行配对的方式的数量。 j表示从02 N -1N位数字范围的排列。
  • 使用上面的递归关系并填充递归关系的所有可能的dp状态。
  • 最后,打印dp状态,其中有N个红色糖果并且选择了N个蓝色糖果,即dp [i] [2 n -1]

下面是上述方法的实现:

Python3

# Python program to implement
# the above approach
  
  
# Function to count ways to select N distinct
# pairs of candies with different colors
def numOfWays(a, n):
 
 
    # dp[i][j]: Stores count of ways to make
    # pairs between i red candies and N blue candies
    dp = [[0]*((1 << n)+1) for _ in range(n + 1)]
 
    # If there is no red and blue candy,
    # the count of ways to make n pairs is 1
    dp[0][0] = 1
 
    # i: Stores count of red candy
    for i in range(n):
 
        # j generates a permutation of blue
        # candy of selected / not selected
        # as a binary number with n bits
        for j in range(1 << n):
 
            if dp[i][j] == 0:
                continue
    
            # Iterate over the range [0, n]   
            for k in range(n):
 
                # Create a mask with only
                # the k-th bit as set
                mask = 1 << k
                 
                # If Kth bit of mask is
                # unset  and mat[i][k] = 1
                if not(mask & j) and a[i][k]:
                    dp[i + 1][j | mask] += dp[i][j]
                     
         
                     
    # Return the dp states, where n red
    # and n blue candies are selected
    return dp[n][(1 << n)-1]
 
 
 
# Driver Code
if __name__ == "__main__":
    n = 3
    mat = [[0, 1, 1],
           [1, 0, 1],
           [1, 1, 1]]
    print(numOfWays(mat, n))
输出:
3

时间复杂度: O(N 2 * 2 N )
辅助空间: O(N * 2 N )