康拓展开

康拓展开

康拓展开在求字典序问题上是一个十分强大的算法

首先,康拓展开是形如以下的式子

X=an(n1)!+an1(n2)!+...+a10!

下面介绍一下此式在康拓展开中的含义

  • 首先我们假设有一个长为n的字符串s,下标从0开始
  • ai的值是在后i-1个字符中,其中比s[n-i]小的字符个数
  • 那么在此字符串在所有的排列中,字典序比此字符串小的有X个

那么我们就可以快速解决一些字典序的问题


首先就是如上所说的求有多少个比这个字典序小的字符串数,代码如下

@Frosero
#include <iostream>
#include <cstring>

using namespace std;

long long mul(long long n){
    if(n == 0 || n == 1) return n;
    return n * mul(n - 1);
}

long long KT(string &s){  //康拓展开
    long long ans = 0;
    for(string::size_type i=0;i<s.size();i++){
        long long ai = 0;     
        for(string::size_type j=i+1;j<s.size();j++){ //计算ai
            if(s[i] > s[j]){
                ai++;
            }
        }
        ans += ai * mul(s.size() - i - 1);
    }
    return ans;  //若想求此字符串是第几小,则返回ans+1
}

int main(){
    string s = "CAB";
    cout << KT(s);
    return 0;
}

康拓展开的逆用:快速找到第K个字典序的排列

方法:我们可以从高位到低位依次推断系数an,代码如下

@Frosero
#include <iostream>
#include <cstring>
#include <set>
#include <map>
#include <cstdlib>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define LL long long

using namespace std;

long long mul(long long n){
    if(n == 0 || n == 1) return 1;
    return n * mul(n - 1);
}

bool used[25];

void inv_KT(long long k,long long len,long long *a){
    k--;
    memset(used,false,sizeof(used));
    int tot = 0;
    for(int i=len-1;i>=0;i--){
        int ai = k / mul(i);     //确定最高位的系数ai
        int cnt = 0;
        for(int j=1;;j++)if(!used[j]){ //只有未被使用的数字才加入计数cnt
            if(cnt == ai){
                a[tot++] = j;
                used[j] = true;     //used[i]表示数字i是否在前面已经被使用
                break;             //若已被使用则used[i]标记为true
            }
            cnt++;
        }
        k = k % mul(i);        //确定余数,继续进行后面的运算
    }
}

int main(){
    long long K = 5,len = 3,a[25];
    inv_KT(K,len,a);
    for(int i=0;i<len;i++) cout<<a[i]<<" ";
    return 0;
}

一些补充:

  • 目测这个算法只能计算没有重复字符的字符串
  • C++中长度为20的字符串几乎是我们能处理的极限(不考虑高精度,或者用JAVA写肯定是壕无压力处理几万长的字符串)
  • 这里我们用数字来表示示例的顺序,实际中只要建立数字和字符的映射关系即可。这也是这个算法之所以强大之所在!

转载于:https://www.cnblogs.com/ScratchingBear/p/5345843.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值