📜  K反转的排列数

📅  最后修改于: 2021-05-04 20:53:03             🧑  作者: Mango

给定一个数组,将反演定义为对a [i],a [j],使得a [i]> a [j]且i

例子:

Input  : N = 3, K = 1
Output : 2
Explanation :  
Total Permutation of first N number,
123, 132, 213, 231, 312, 321
Permutation with 1 inversion : 132 and 213

Input  : N = 4, K = 2
Output : 5

解决此问题的一种简单方法是记下所有排列,然后检查它们中的求反计数,但通过排列本身进行迭代将花费O(N!)时间,该时间太大。

我们可以使用动态编程方法解决此问题。以下是递归公式。

If N is 0, Count(0, K) = 0

If K is 0, Count(N, 0) = 1 (Only sorted array)

In general case, 
If we have N number and require K inversion, 
Count(N, K) = Count(N - 1, K) + 
              Count(N – 1, K - 1) + 
              Count(N – 1, K – 2) + 
              .... + 
              Count(N – 1, 0)

以上递归公式如何工作?
如果我们有N个数,并且想有K个排列,并且假设(N – 1)个数的所有排列都写在某个地方,则需要将新数(第N个和最大的数)放在(N – 1)个数的所有排列中,并且在添加此数字后其反转计数变为K的那些变量应添加到我们的答案中。现在取那些使(K – 3)求逆的(N – 1)个数的排列集,现在我们可以将这个新的最大数放在最后一个位置3上,那么求反的计数将为K,所以count(N – 1 ,K – 3)应该添加到我们的答案中,对于其他反演也可以给出相同的论点,我们将以上述递归作为最终答案。

下面的代码以记忆的方式在上面的递归之后编写。

C++
// C++ program to find number of permutation
// with K inversion using Memoization
#include 
using namespace std;
 
// Limit on N and K
const int M = 100;
 
// 2D array memo for stopping
// solving same problem again
int memo[M][M];
 
// method recursively calculates
// permutation with K inversion
int numberOfPermWithKInversion(int N, int K)
{
     
    // base cases
    if (N == 0)
        return 0;
    if (K == 0)
        return 1;
 
    // if already solved then
    // return result directly
    if (memo[N][K] != 0)
        return memo[N][K];
 
    // calling recursively all subproblem
    // of permutation size N - 1
    int sum = 0;
    for (int i = 0; i <= K; i++)
    {
 
        // Call recursively only
        // if total inversion
        // to be made are less
        // than size
        if (i <= N - 1)
            sum += numberOfPermWithKInversion(N - 1,
                                              K - i);
    }
 
    // store result into memo
    memo[N][K] = sum;
 
    return sum;
}
 
// Driver code
int main()
{
    int N = 4;
    int K = 2;
    cout << numberOfPermWithKInversion(N, K);
    return 0;
}


Java
// Java program to find number of permutation with
// K inversion using Memoization
 
import java.io.*;
 
class GFG {
     
    // Limit on N and K
    static int M = 100;
 
    // 2D array memo for stopping solving same problem
    // again
    static int memo[][] = new int[M][M];
 
    // method recursively calculates permutation with
    // K inversion
    static int numberOfPermWithKInversion(int N, int K)
    {
         
        // base cases
        if (N == 0)
            return 0;
        if (K == 0)
            return 1;
 
        // if already solved then return result directly
        if (memo[N][K] != 0)
            return memo[N][K];
 
        // calling recursively all subproblem of
        // permutation size N - 1
        int sum = 0;
        for (int i = 0; i <= K; i++) {
             
            // Call recursively only if total inversion
            // to be made are less than size
            if (i <= N - 1)
                sum += numberOfPermWithKInversion(N - 1,
                                                  K - i);
        }
 
        // store result into memo
        memo[N][K] = sum;
 
        return sum;
    }
 
    // Driver code to test above methods
    public static void main(String[] args)
    {
        int N = 4;
        int K = 2;
        System.out.println(numberOfPermWithKInversion(N, K));
    }
}
 
// This code is contributed by vt_m.


Python3
# Python3 program to find number of permutation
# with K inversion using Memoization
 
# Limit on N and K
M = 100
 
# 2D array memo for stopping 
# solving same problem again
memo = [[0 for i in range(M)] for j in range(M)]
  
# method recursively calculates
# permutation with K inversion
def numberOfPermWithKInversion(N, K):
 
    # Base cases
    if (N == 0): return 0
    if (K == 0): return 1
 
    # If already solved then
    # return result directly
    if (memo[N][K] != 0):
        return memo[N][K]
 
    # Calling recursively all subproblem
    # of permutation size N - 1
    sum = 0
    for i in range(K + 1):
     
        # Call recursively only if
        # total inversion to be made
        # are less than size
        if (i <= N - 1):
            sum += numberOfPermWithKInversion(N - 1, K - i)
     
    # store result into memo
    memo[N][K] = sum
 
    return sum
 
# Driver code
N = 4; K = 2
print(numberOfPermWithKInversion(N, K))
 
# This code is contributed by Anant Agarwal.


C#
// C# program to find number of
// permutation with K inversion
// using Memoization
using System;
 
class GFG
{
 
// Limit on N and K
static int M = 100;
 
// 2D array memo for stopping
// solving same problem again
static int [,]memo = new int[M, M];
 
// method recursively calculates
// permutation with K inversion
static int numberOfPermWithKInversion(int N,
                                      int K)
{
     
    // base cases
    if (N == 0)
        return 0;
    if (K == 0)
        return 1;
 
    // if already solved then
    // return result directly
    if (memo[N, K] != 0)
        return memo[N, K];
 
    // calling recursively all
    // subproblem of permutation
    // size N - 1
    int sum = 0;
    for (int i = 0; i <= K; i++)
    {
         
        // Call recursively only if
        // total inversion to be
        // made are less than size
        if (i <= N - 1)
            sum += numberOfPermWithKInversion(N - 1,
                                              K - i);
    }
 
    // store result into memo
    memo[N, K] = sum;
 
    return sum;
}
 
// Driver Code
static public void Main ()
{
    int N = 4;
    int K = 2;
    Console.WriteLine(numberOfPermWithKInversion(N, K));
}
}
 
// This code is contributed by ajit


PHP


Javascript


输出:

5