Number of permutation with K inversions

本文介绍了一种计算给定N个数中有确切K个逆序数的排列总数的方法。通过递归和记忆化搜索,实现了高效计算。文章还提供了一个C++示例程序来说明算法的实现。

Given an array, an inversion is defined as a pair a[i], a[j] such that a[i] > a[j] and i < j. We are given two numbers N and k, we need to tell how many permutation of first N number have exactly K inversion.

给定一个数组,inversion被定义为a [i],a [j],使得[i]> a [j]和i < j。 我们给出两个数字N和k,我们需要计算出 N 个数的排列有多少个正好是K个inversion。

例如:
输入 : N = 3, K = 1
输出 : 2
Explanation :
全部的可能情况:
123, 132, 213, 231, 312, 321
符合条件的情况 : 132 and 213

输入 : N = 4, K = 2

输出 : 2

解法的伪代码如下:

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(N1, K - 1) + 
              Count(N1, K2) + 
              .... + 
              Count(N1, 0)

其解法思想如下:

如果我们有N个数并希望有K个inversion,并且假设(N-1)个数的所有inversion写在某个地方,那么新数(第N个数,即最大的数)需要被置于(N-1)个数的所有inversion中,在我们的答案中应该加上那些inversion计数变为K后的组合。

简单的说就是将第N个数插入在前N-1个数的所有组合中,将inversion=k的情况相加。
下面给出了各个情况的示意图:
1. 前n-1个已经组成了inversions=k,则第n个只需要插入在最后。
image
2. 前n-1个已经组成了inversions=k-1,则第n个需要往前插 1 位,让inversions=k。
image
3. 前n-1个已经组成了inversions=k-2,则第n个需要往前插 2 位,让inversions=k。
image



依次类推:
image

实现代码如下(c++):

// C++ program to find number of permutation with
// K inversion using Memoization
#include <bits/stdc++.h>
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 to test above methods
int main()
{
    int N = 4;
    int K = 2;
    cout << numberOfPermWithKInversion(N, K);
    return 0;
}

Output:

5

### k折交叉验证中使用排列重要性 在机器学习实践中,特征选择对于提升模型性能至关重要。排列重要性是一种衡量特征对模型预测能力影响的方法,在k折交叉验证框架下应用此技术能更稳健地评估各个特征的重要性。 #### 计算排列重要性 为了计算排列重要性,首先需要构建一个基础模型,并通过k折交叉验证对其进行训练和初步评价[^4]。接着,针对每次折叠后的验证集执行如下操作: - 对于每一个待测特征f_i,保存当前模型对该特征所在验证集的初始预测得分S_0。 - 随机打乱该特征对应的列向量值,保持其他所有输入不变,再次运行相同的预测过程获得新的分数S_p。 - 排列重要性的定义为两者差异ΔS=S_0-S_p;正值表示移除或扰乱特定特征降低了模型的表现力,负数则意味着相反效果。 ```python from sklearn.inspection import permutation_importance import numpy as np def compute_permutation_importances(model, X_val, y_val): result = permutation_importance( model, X_val, y_val, n_repeats=30, random_state=42, scoring='accuracy' ) sorted_idx = result.importances_mean.argsort() fig, ax = plt.subplots(figsize=(8, 6)) ax.boxplot(result.importances[sorted_idx].T, vert=False, labels=X.columns[sorted_idx]) ax.set_title("Permutation Importances (test set)") fig.tight_layout() return result.importances_mean[sorted_idx], list(X.columns[sorted_idx]) for train_index, test_index in kf.split(X): X_train, X_test = X.iloc[train_index], X.iloc[test_index] y_train, y_test = y.iloc[train_index], y.iloc[test_index] clf.fit(X_train, y_train) imp_means, feat_names = compute_permutation_importances(clf, X_test, y_test) ``` 上述代码展示了如何在一个典型的k折循环内实现排列重要性的计算流程。这里采用了`sklearn.inspection.permutation_importance()`函数简化了具体实施细节[^1]。 #### 应用排列重要性进行特征选择 基于所得到的重要度评分,可以选择保留那些具有较高贡献率的变量用于后续建模工作。一种简单策略是设定阈值t,仅选取其均值大于等于t的前n个最重要特性参与最终分析。此外,也可以考虑采用递归消除法(recursive feature elimination,RFE)结合排列重要性来进行更加精细的选择[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值