给出4个数字N,M,X,Y,分别代表第一件物品的N个数字和第二件物品的M个数字,任务是找出N+M的物品排列在一起的数量,使第一件物品不超过X,第二件物品不超过Y。
例子。
输入。 N = 2, M = 1, X = 1, Y = 10
输出。 1
**解释。**我们把第一项标为1
,第二项标为2,唯一可能的排列是121。输入。 N = 2, M = 3, X = 1, Y = 2
输出。 5
**解释。**让我们把第一项标记为1,第二项标记为2。
可能的排列是12122, 12212, 21212, 21221, 22121。
办法:要解决这个问题,请遵循以下的观察和步骤。
有许多可能性,先放X个项目,再放Y个项目。所以要检查每一种可能性,我们可以使用动态编程。
由于每一步N、M、X和Y都会发生变化,所以dp[]数组会有4种状态。
让f(n, m, x, y)代表选择以x个连续的第一类元素和y个连续的元素进行有效排列的方法的数量。
所以可以有2种情况。我们放置第一类元素:f(n-1, m, x-1, y)或者
我们选择第二类元素:f(n, m-1, x, y-1)所以 f(n, m, x, y) = f(n - 1, m, x - 1, y) + f(n, m - 1, x, y - 1)
这里的情况是,如果m或n变成了0,那么在下一次迭代中,我们不能使用另一个连续的元素,如果第1或第2类型。
按照下面的步骤来实现这个方法。
- 创建一个递归函数和一个四维数组(例如dp[]),用来存储每个状态。
- 递归调用上面提到的函数,保持提到的边缘情况。
- 返回存储在**dp[N][M][X][Y]**的最终值作为所需的答案。
下面是上述方法的实现。
C++
// C++ code to implement the approach.
#include <bits/stdc++.h>
using namespace std;
// dp array
int dp[101][101][11][11];
// To store original value of X, Y
int limit_f = 0, limit_s = 0;
// Function to find number of ways
int numofways(int n, int m, int x, int y)
{
// Base case if n1+n2 is 0 that all
// items are placed then 1 arrangement
// is complete
if (n + m == 0)
return 1;
int f = 0, s = 0;
if (dp[n][m][x][y] != -1)
// The value is precomputed or not
return dp[n][m][x][y];
// If 1st item can be placed
if (n > 0 && x > 0)
// Since we place the first item
// there are limit_s second items
// can be placed consecutively
f = numofways(n - 1, m, x - 1, limit_s);
if (m > 0 && y > 0)
// Since we place the second item there
// are limit_f first item can be
// placed consecutively
s = numofways(n, m - 1, limit_f, y - 1);
// Total number of arrangements is
// addition of 2
return dp[n][m][x][y] = (f + s);
}
// Driver code
int main()
{
int N = 2, M = 3, X = 1, Y = 2;
limit_f = X, limit_s = Y;
// Initialization
for (int i = 0; i <= N; i++) {
for (int j = 0; j <= M; j++) {
for (int k = 0; k <= X; k++) {
for (int m = 0; m <= Y; m++)
dp[i][j][k][m] = -1;
}
}
}
// Function call
cout << numofways(N, M, X, Y) << endl;
return 0;
}
输出
5
时间复杂度。 O(N * M * X * Y)
辅助空间。 O(N * M * X * Y)。