📌  相关文章
📜  大小为 N 且相邻对的乘积之和等于 K 的二进制数组的计数

📅  最后修改于: 2022-05-13 01:56:04.322000             🧑  作者: Mango

大小为 N 且相邻对的乘积之和等于 K 的二进制数组的计数

给定两个整数NK ,任务是找到大小为 N 的可能二进制数组的总数,使得该数组中相邻对的乘积之和恰好等于K

例子:

朴素方法:最简单的方法是找到数组的所有可能组合,并单独检查每个组合是否其和等于 K。
时间复杂度: O(2^N)

高效方法:上述简单方法可以通过在大小为 (K+1, N+1, 2) 的 3d 矩阵 dp 中记忆每个递归调用的结果来优化,即 dp[K+1][N+1][ 2]。在这里,这个 dp 矩阵的每个节点,比如dp[a][b]表示大小b具有总和a并且最后一个元素是c的可能组合的数量,其中 c 只能是 0 或 1。现在按照以下步骤解决这个问题:

  1. 首先,创建一个带参数的函数组合(N, idx, prev, val, K) ,其中N是要形成的数组的大小, idx是数组的所有可能组合都可能的索引(最初为 0) , prev是新形成的数组中的前一个元素(只能是 0 或 1), val是直到 idx 的乘积之和, K是连续元素的乘积之和。此函数将返回可能组合的数量,直到索引idx具有 sum val和前一个元素prev 。此外,在返回时记住结果。
  2. 现在,从主函数调用上述函数combinationsPossible两次,所有初始值相同,但仅将prev 更改为一次为0,另一次为1,以计算从0 和1 开始的所有数组的可能组合。
  3. 在每次通话中检查基本情况,即:
    • 如果val>K :返回 0,因为在此索引之后有 0 个组合的总和 K 已超过总和。
    • 如果idx=N-1 :这意味着形成了大小为 N 的整个数组。因此,如果valK ,则只返回 1,即可能的组合数。否则,返回 0。
  4. 此外,在每个递归调用中,检查其结果是否已被记忆。如果是,那么只需从dp数组中返回它。
  5. 现在,如果前一个元素是 1,则进行两次递归调用:
    • 考虑以 1 作为当前元素的可能组合。因此,在此调用中将val增加 1,因为当前元素和前一个元素的乘积 (1*1=1) 将为当前总和加 1。
    • 考虑以 0 作为当前元素的可能组合。在这种情况下, val将保持不变。
  6. 如果前一个元素为 0,则还进行两次递归调用,一次将带有 1 的组合视为当前元素,另一个将带有 0 的组合视为当前元素。在这两种情况下, val都将保持不变。
  7. 将上述四个函数调用返回的所有值相加,记忆后从当前函数返回这个相加值。
  8. 根据以上观察打印答案。

下面是上述方法的实现:

C++
// C++ program for the above approach
 
#include 
using namespace std;
 
// Function to return the number of total
// possible combinations of 0 and 1 to form
// an array of size N having sum of product
// of consecutive elements K
int combinationsPossible(int N, int idx, int prev, int val,
                         int K,
                         vector > >& dp)
{
 
    // If value is greater than K, then
    // return 0 as no combination is
    // possible to have sum K
    if (val > K) {
        return 0;
    }
 
    // Check if the result of this recursive
    // call is memoised already, if it is then
    // just return the previously calculated result
    if (dp[val][idx][prev] != -1) {
        return dp[val][idx][prev];
    }
 
    // Check if the value is equal to K at N, if
    // it is then return 1 as this combination
    // is possible. Otherwise return 0.
    if (idx == N - 1) {
        if (val == K) {
            return 1;
        }
        return 0;
    }
    int ans = 0;
 
    // If previous element is 1
    if (prev == 1) {
 
        // If current element is 1 as well, then
        // add 1 to value
        ans += combinationsPossible(N, idx + 1, 1, val + 1,
                                    K, dp);
 
        // If current element is 0, then value
        // will remain same
        ans += combinationsPossible(N, idx + 1, 0, val, K,
                                    dp);
    }
 
    // If previous element is 0, then value will
    // remain same irrespective of the current element
    else {
        ans += combinationsPossible(N, idx + 1, 1, val, K,
                                    dp);
        ans += combinationsPossible(N, idx + 1, 0, val, K,
                                    dp);
    }
 
    // Memoise and return the ans
    return dp[val][idx][prev] = ans;
}
 
// Driver Code
int main()
{
    int N = 5;
    int K = 3;
    vector > > dp(
        K + 1,
        vector >(N + 1, vector(2, -1)));
 
    // As the array can be started by 0 or 1, so take both
    // cases while calculating the total possible
    // combinations
    cout << (combinationsPossible(N, 0, 0, 0, K, dp)
             + combinationsPossible(N, 0, 1, 0, K, dp));
}


Java
// Java program for the above approach
import java.util.*;
 
class GFG
{
 
    // Function to return the number of total
    // possible combinations of 0 and 1 to form
    // an array of size N having sum of product
    // of consecutive elements K
    static int combinationsPossible(int N, int idx, int prev,
                                    int val, int K, int[][][] dp)
    {
 
        // If value is greater than K, then
        // return 0 as no combination is
        // possible to have sum K
        if (val > K) {
            return 0;
        }
 
        // Check if the result of this recursive
        // call is memoised already, if it is then
        // just return the previously calculated result
        if (dp[val][idx][prev] != -1) {
            return dp[val][idx][prev];
        }
 
        // Check if the value is equal to K at N, if
        // it is then return 1 as this combination
        // is possible. Otherwise return 0.
        if (idx == N - 1) {
            if (val == K) {
                return 1;
            }
            return 0;
        }
        int ans = 0;
 
        // If previous element is 1
        if (prev == 1) {
 
            // If current element is 1 as well, then
            // add 1 to value
            ans += combinationsPossible(N, idx + 1, 1, val + 1, K, dp);
 
            // If current element is 0, then value
            // will remain same
            ans += combinationsPossible(N, idx + 1, 0, val, K, dp);
        }
 
        // If previous element is 0, then value will
        // remain same irrespective of the current element
        else {
            ans += combinationsPossible(N, idx + 1, 1, val, K, dp);
            ans += combinationsPossible(N, idx + 1, 0, val, K, dp);
        }
 
        // Memoise and return the ans
        dp[val][idx][prev] = ans;
        return dp[val][idx][prev];
    }
 
    // Driver Code
    public static void main(String[] args) {
        int N = 5;
        int K = 3;
        int[][][] dp = new int[K + 1][N + 1][2];
        for (int i = 0; i < K + 1; i++) {
            for (int j = 0; j < N + 1; j++) {
                for (int k = 0; k < 2; k++)
                    dp[i][j][k] = -1;
            }
        }
       
        // As the array can be started by 0 or 1, so take both
        // cases while calculating the total possible
        // combinations
        System.out.print(combinationsPossible(N, 0, 0, 0, K, dp) + combinationsPossible(N, 0, 1, 0, K, dp));
    }
}
 
// This code is contributed by 29AjayKumar


Python3
# Python 3 program for the above approach
 
# Function to return the number of total
# possible combinations of 0 and 1 to form
# an array of size N having sum of product
# of consecutive elements K
def combinationsPossible(N, idx, prev, val, K, dp):
    # If value is greater than K, then
    # return 0 as no combination is
    # possible to have sum K
    if (val > K):
        return 0
 
    # Check if the result of this recursive
    # call is memoised already, if it is then
    # just return the previously calculated result
    if (dp[val][idx][prev] != -1):
        return dp[val][idx][prev]
 
    # Check if the value is equal to K at N, if
    # it is then return 1 as this combination
    # is possible. Otherwise return 0.
    if (idx == N - 1):
        if(val == K):
            return 1
        return 0
    ans = 0
 
    # If previous element is 1
    if (prev == 1):
        # If current element is 1 as well, then
        # add 1 to value
        ans += combinationsPossible(N, idx + 1, 1, val + 1, K, dp)
 
        # If current element is 0, then value
        # will remain same
        ans += combinationsPossible(N, idx + 1, 0, val, K, dp)
 
    # If previous element is 0, then value will
    # remain same irrespective of the current element
    else:
        ans += combinationsPossible(N, idx + 1, 1, val, K, dp)
        ans += combinationsPossible(N, idx + 1, 0, val, K, dp)
 
    # Memoise and return the ans
    dp[val][idx][prev] = ans
    return ans
 
# Driver Code
if __name__ == '__main__':
    N = 5
    K = 3
    dp = [[[-1 for i in range(2)] for j in range(N+1)] for k in range(K+1)]
    # As the array can be started by 0 or 1, so take both
    # cases while calculating the total possible
    # combinations
    print(combinationsPossible(N, 0, 0, 0, K, dp) + combinationsPossible(N, 0, 1, 0, K, dp))
     
    # This code is contributed by SURENDRA_GANGWAR.


C#
// C# program for the above approach
using System;
class GFG
{
   
    // Function to return the number of total
    // possible combinations of 0 and 1 to form
    // an array of size N having sum of product
    // of consecutive elements K
    static int combinationsPossible(int N, int idx,
                                    int prev, int val,
                                    int K, int[, , ] dp)
    {
 
        // If value is greater than K, then
        // return 0 as no combination is
        // possible to have sum K
        if (val > K) {
            return 0;
        }
 
        // Check if the result of this recursive
        // call is memoised already, if it is then
        // just return the previously calculated result
        if (dp[val, idx, prev] != -1) {
            return dp[val, idx, prev];
        }
 
        // Check if the value is equal to K at N, if
        // it is then return 1 as this combination
        // is possible. Otherwise return 0.
        if (idx == N - 1) {
            if (val == K) {
                return 1;
            }
            return 0;
        }
        int ans = 0;
 
        // If previous element is 1
        if (prev == 1) {
 
            // If current element is 1 as well, then
            // add 1 to value
            ans += combinationsPossible(N, idx + 1, 1,
                                        val + 1, K, dp);
 
            // If current element is 0, then value
            // will remain same
            ans += combinationsPossible(N, idx + 1, 0, val,
                                        K, dp);
        }
 
        // If previous element is 0, then value will
        // remain same irrespective of the current element
        else {
            ans += combinationsPossible(N, idx + 1, 1, val,
                                        K, dp);
            ans += combinationsPossible(N, idx + 1, 0, val,
                                        K, dp);
        }
 
        // Memoise and return the ans
        return dp[val, idx, prev] = ans;
    }
 
    // Driver Code
    public static void Main()
    {
        int N = 5;
        int K = 3;
        int[, , ] dp = new int[K + 1, N + 1, 2];
        for (int i = 0; i < K + 1; i++)
            for (int j = 0; j < N + 1; j++)
                for (int l = 0; l < 2; l++)
                    dp[i, j, l] = -1;
 
        // As the array can be started by 0 or 1, so take
        // both cases while calculating the total possible
        // combinations
        Console.WriteLine(
            combinationsPossible(N, 0, 0, 0, K, dp)
            + combinationsPossible(N, 0, 1, 0, K, dp));
    }
}
 
// This code is contributed by ukasp.


Javascript



输出
2

时间复杂度: O(N*K)