大小为 P 的有效数组的计数,其中元素在 [1, N] 范围内具有至少 M 距离的重复项
给定三个整数N、M和P ,任务是找到可以创建的大小为P且每个元素在[1, N] 范围内的有效数组的总数,使得重复项至少相隔 M距离。
示例:
Input: N = 2, M = 0, P = 3
Output: 6
Explanation: All valid arrays are: {1, 2, 1}, {1, 1, 2}, {2, 1, 1}, {2, 2, 1}, {2, 1, 2}, {1, 2, 2}.
Input: N = 2, M = 1, P = 4
Output: 2
Explanation: All valid arrays are: {1, 2, 1, 2}, {2, 1, 2, 1}
方法:问题可以在动态规划的帮助下解决,
- 在每个索引处有两种可能的选择是:要么我们追加已使用的元素,相距至少 M距离,要么我们追加一个新元素并减少未使用字符的数量。
- 要处理这个问题,请使用递归动态编程。
- 要加快递归调用,请使用记忆化,以便不再计算已计算的状态。
- Let’s define: dp[i][j][k] as the number of arrays till i-th position in which j unique elements are present and k be elements which are not used
- 每一步都有两个选项:
1. 选择之前出现的元素,j 和 k 不会改变,因为使用和未使用的元素的数量不会改变: dp[i+1][j][k]
2. 选择从未使用过的元素,此时使用的字符数加1,未使用的字符数减1: dp[i+1][j+1][k-1]
dp[i][j][k]将是上述两个步骤的总和,表示为:
dp[i][j][k] = dp[i+1][j][k] + dp[i+1][j+1][k-1]
- 最终答案将是dp[0][0][N]。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Function to calculate the total
// number of arrays
int calculate(int position, int used, int unused, int P,
int M, vector > >& dp)
{
// If the size of the array is P
if (position == P) {
// Check if all elements are
// used atlease once
return unused == 0 ? 1 : 0;
}
// Check if this state is already
// calculated
if (dp[position][used][unused] != -1)
return dp[position][used][unused];
// Initialize the result
int result = 0;
// Use a number from the list of
// unused numbers
if (unused > 0) {
// There are 'unused' number of
// favourable choices
result += calculate(position + 1, used + 1,
unused - 1, P, M, dp)
* unused;
}
// Use a number from already present number
// atlease M distance back
if (used > M) {
// There are 'used - M' number of
// favourable choices
result += calculate(position + 1,
used, unused, P,
M, dp)
* (used - M);
}
// Store the result
return dp[position][used][unused] = result;
}
// Function to solve the problem
int solve(int N, int P, int M)
{
// Initialize DP table : dp[i][j][j]
// i : current position/index
// j : number of used elements
// k : number of unused elements
vector > > dp(
101,
vector >(101,
vector(101, -1)));
return calculate(0, 0, N, P, M, dp);
}
// Driver Code
int main()
{
int N = 2, M = 0, P = 3;
cout << solve(N, P, M);
}
Java
// Java program for the above approach
import java.io.*;
class GFG
{
// Function to calculate the total
// number of arrays
static int calculate(int position, int used, int unused, int P,
int M, int dp[][][])
{
// If the size of the array is P
if (position == P)
{
// Check if all elements are
// used atlease once
return unused == 0 ? 1 : 0;
}
// Check if this state is already
// calculated
if (dp[position][used][unused] != -1)
return dp[position][used][unused];
// Initialize the result
int result = 0;
// Use a number from the list of
// unused numbers
if (unused > 0) {
// There are 'unused' number of
// favourable choices
result += calculate(position + 1, used + 1,
unused - 1, P, M, dp)
* unused;
}
// Use a number from already present number
// atlease M distance back
if (used > M)
{
// There are 'used - M' number of
// favourable choices
result += calculate(position + 1,
used, unused, P,
M, dp)
* (used - M);
}
// Store the result
return dp[position][used][unused] = result;
}
// Function to solve the problem
static int solve(int N, int P, int M)
{
// Initialize DP table : dp[i][j][j]
// i : current position/index
// j : number of used elements
// k : number of unused elements
int[][][] dp = new int[101][101][101];
for(int i = 0; i < 101; i++)
{
for(int j = 0; j < 101; j++)
for(int k = 0; k < 101; k++)
dp[i][j][k] = -1;
}
return calculate(0, 0, N, P, M, dp);
}
// Driver Code
public static void main(String[] args)
{
int N = 2, M = 0, P = 3;
System.out.println(solve(N, P, M));
}
}
// This code is contributed by dwivediyash
Python3
# Python 3 program for the above approach
# Function to calculate the total
# number of arrays
def calculate(position, used, unused, P, M, dp):
# If the size of the array is P
if (position == P):
# Check if all elements are
# used atlease once
if unused == 0:
return 1
else:
return 0
# Check if this state is already
# calculated
if (dp[position][used][unused] != -1):
return dp[position][used][unused]
# Initialize the result
result = 0
# Use a number from the list of
# unused numbers
if (unused > 0):
# There are 'unused' number of
# favourable choices
result += calculate(position + 1, used + 1,unused - 1, P, M, dp)* unused
# Use a number from already present number
# atlease M distance back
if (used > M):
# There are 'used - M' number of
# favourable choices
result += calculate(position + 1,used, unused, P,M, dp)* (used - M)
dp[position][used][unused] = result
# Store the result
return dp[position][used][unused]
# Function to solve the problem
def solve(N, P, M):
# Initialize DP table : dp[i][j][j]
# i : current position/index
# j : number of used elements
# k : number of unused elements
dp = [[[-1 for i in range(101)] for i in range(101)] for j in range(101)]
return calculate(0, 0, N, P, M, dp)
# Driver Code
if __name__ == '__main__':
N = 2
M = 0
P = 3
print(solve(N, P, M))
# This code is contributed by SURENDRA_GANGWAR.
C#
// C# program for the above approach
using System;
public class GFG
{
// Function to calculate the total
// number of arrays
static int calculate(int position, int used, int unused, int P,
int M, int [,,]dp)
{
// If the size of the array is P
if (position == P)
{
// Check if all elements are
// used atlease once
return unused == 0 ? 1 : 0;
}
// Check if this state is already
// calculated
if (dp[position,used,unused] != -1)
return dp[position,used,unused];
// Initialize the result
int result = 0;
// Use a number from the list of
// unused numbers
if (unused > 0)
{
// There are 'unused' number of
// favourable choices
result += calculate(position + 1, used + 1,
unused - 1, P, M, dp)
* unused;
}
// Use a number from already present number
// atlease M distance back
if (used > M)
{
// There are 'used - M' number of
// favourable choices
result += calculate(position + 1,
used, unused, P,
M, dp)
* (used - M);
}
// Store the result
return dp[position,used,unused] = result;
}
// Function to solve the problem
static int solve(int N, int P, int M)
{
// Initialize DP table : dp[i,j,j]
// i : current position/index
// j : number of used elements
// k : number of unused elements
int[,,] dp = new int[101,101,101];
for(int i = 0; i < 101; i++)
{
for(int j = 0; j < 101; j++)
for(int k = 0; k < 101; k++)
dp[i, j, k] = -1;
}
return calculate(0, 0, N, P, M, dp);
}
// Driver Code
public static void Main(String[] args)
{
int N = 2, M = 0, P = 3;
Console.WriteLine(solve(N, P, M));
}
}
// This code is contributed by shikhasingrajput
Javascript
输出
6
时间复杂度:O(NMP) (因为三个因变量)
辅助空间:O(NMP) (DP矩阵的大小)