首页 > 其他分享 >康托展开 全排列与其字典序的双映射转换

康托展开 全排列与其字典序的双映射转换

时间:2023-04-26 21:37:30浏览次数:44  
标签:include 映射 int 排列 序列 康托 Fact 字典

对于给定的序列1 2 3,其全排列有6种,按照字典序从小到大即为

0 1   2 3 4 5
1,2,3 1,3,2 2,1,3 2,3,1 3,1,2 3,2,1

可以看出,每个全排列序列都唯一对应一个字典序数(从0开始),那么,有什么方法可以根据序列求出其对应的字典序或者根据字典序来推断其对应序列呢

一个朴素的思想,我们使用深搜或者next_permutation函数来对序列按照字典序来遍历,然后记录其出现的位置,最坏时间复杂度为N!

可以看出,仅仅是求出其字典序已经是N!的时间复杂度了,如果我们有别的查找询问的操作,会在N!基础上进行,这是十分大的时间复杂度

我们不妨这样想,如果能求出一个序列之前序列的个数,根据字典序,也就是所有小于当前序列的序列的个数,那所求序列的字典序不就是这个个数吗

对于序列3,4,5,2,1,我们来分析一下

首位为3,要找比整个序列小的序列,只需要找首位比3小的数所构成的序列,可以知道有1,2两个数比3小,则以1,2开头的序列数就是 2*(5-1)!(这里的阶乘即为后四位用剩下四个数的全排列)

第二位为4,我们去寻找比4小的而且并未作为前缀的数,有1,2(3在序列中已经使用作为第一位),因此一共有2*(4-1)!

第三位为5,寻找比5小且未使用的数,1,2,共有2*(3-1)!;

第四位为2,寻找比2小且未使用的数,1,共有1*(2-1)!;

最后位为1,寻找比1小且未使用的数,没有,即为0个,共有0*(1-1)!

综上,所有比34521小的序列就被我们都找出来了,因此加起来就有

2*(4-1)!+2*(3-1)!+1*(2-1)!+0*(1-1)个,得数就是序列34521的字典序

综上我们可以得出这样的公式,对于一个长度为n的序列,其某个全排列序列对应的字典序为

an(n-1)!+an((n-1)-1)!+........+a2(2-1)!+a1(1-1)!

其中an是小于A[n]且未被当作前缀的元素的个数

这样,我们就可以在O(N 2)的时间复杂度内求出其对应字典序了

给出实现代码

#include<algorithm>
#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;
long long Fact[50];//存储阶乘的数组
void fact(int N)//阶乘初始化函数
{
    if (N == 0)
    {
        Fact[N] = 1; return;
    }
    fact(N - 1);
    Fact[N] = Fact[N - 1] * N;
}
int Coutor(vector<int>&A)//康托展开实现函数
{
    int ans = 0;//答案
    for (int i = 0; i < A.size(); i++)//从最高位开始扫描每一位
    {
        int K = 0;//比这一位小的数的个数
            for (int j = i+1/*这里加一即为避免前缀元素的重复计入*/; j < A.size(); j++)
        {
                if (A[i] > A[j])K++;
        }
            ans += K * Fact[A.size() - i - 1];//按照公式计算
    }
    return ans;
}
int main()
{
    fact(20);//初始化阶乘数组
    vector<int>A={1,2,3};//初始化排列数组
    do {
        cout << Coutor(A)<<endl;//输出字典序
    } while (next_permutation(A.begin(), A.end()));//求其全排列
    return 0;
}

 

这样就可以求出从全排列到期字典序了,其实康托展开也可以看作从全排列到字典序转换的哈希函数

但是,还么有完,既然开头我们就说了,康托展开是构造全排列序列与其字典序的双重映射,那么我们如何逆过来,也就是

已知一个全排列的字典序,如何将其展开为位于此字典序上的全排列?其实很简单

我们只需要逐个位来除以刚才乘上的阶乘,得到的整数就是该位上的数比多少数大,以此类推就可以推出此字典序对应的全排列序列

这里给出一个例子,对于五位全排列5,4,3,2,1,其字典序为119(注意从0开始计算),最高位到最低位的阶乘值依次是4!=24,3!=6,2!=2,1!=1,0!=1

因此

119/24=4......23,比四个数大的数为5

23/6=3.......5,比三个数大的数为4

5/2=2.......1,比两个数大的数为3

1/1=1......0,比一个数大的数为2

0/1=0 ,比零个数大的数为1

这样我们就找出了字典序119所对应的序列54321

给出代码实现

#include<algorithm>
#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;
long long Fact[50];
void fact(int N)
{
    if (N == 0)
    {
        Fact[N] = 1; return;
    }
    fact(N - 1);
    Fact[N] = Fact[N - 1] * N;
}
vector<int> incoutor(int Dict, int len)
{
    bool Visited[10] = { false };//使用标记数组
    int cnt = 0;//存储an
    vector<int>C;//结果存储
    for (int i = 0; i < len; i++)
    {
        cnt = Dict / Fact[len - i - 1];
        Dict %= Fact[len - i - 1];//更新Dict和cnt
        for (int j = 1; j <= len; j++)
        {
            if (Visited[j])continue;//如果j已经收入了,掠过本此操作
            if (!cnt)//当cnt为0的时候说明找到了相应的j,进行存入与收入标记
            {
                Visited[j] = true;
                C.push_back(j);
                break;
            }
            cnt--;
        }
    }
    return C;
}
int main()
{
    fact(20);
    auto C = incoutor(119, 5);
    for (auto X : C)
    {
        cout << X;
    }
    return 0;
}
 

 

标签:include,映射,int,排列,序列,康托,Fact,字典
From: https://www.cnblogs.com/WKWKSL/p/17357398.html

相关文章

  • 如何通过frp服务将EasyCVR映射到公网进行访问和运维?
    EasyCVR平台可在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,实现视频资源的鉴权管理、按需调阅、全网分发、智能分析等。平台可提供视频监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、集群、电子地图、H.265视频自动转码、智能分析等......
  • 03.关系映射
    一、实体关系实体——数据实体,实体关系指的就是数据与数据之间的关系例如:用户和角色、房屋和楼栋、订单和商品实体关系分为以下四种:一对一关联实例:学生和校园卡、人和身份证、用户基本信息和详情数据表关系:主键关联(用户表主键和详情主键相同时,表示是匹配的数据)学生......
  • pandas.DataFrame.groupby—使用映射器或通过一系列列对数据框进行分组
    语法格式DataFrame.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=_NoDefault.no_default, squeeze=_NoDefault.no_default, observed=False, dropna=True)常用的几个参数解释:by:可接受映射、函数、标签或标签列表。用于确定分组。ax......
  • POJ - 3764 XOR&&dfs 01字典树
    Inanedge-weightedtree,thexor-lengthofapathpisdefinedasthexorsumoftheweightsofedgesonp:{xor}length§=\oplus{e\inp}w(e)⊕isthexoroperator.Wesayapaththexor-longestpathifithasthelargestxor-length.Givenanedge-weigh......
  • kettle从入门到精通 第十六课 kettle 映射 (子转换)02
    1、上节讲的子映射里面只有一个转换(类似一个java类里面只有一个公共方法),本次讲解的有两个,实际上可以有任意多个(一个java类里面有多个公共方法)。两个转换分别计算x+y和x*y。 2、命名参数:定义一些变量传递到子转换里面。 3、输入1)Availableinputs可以点击加号增加多个输入,......
  • Codeforces Round #285 (Div. 2) B. Misha and Changing Handles map 映射
    MishahackedtheCodeforcessite.Thenhedecidedtoletalltheuserschangetheirhandles.Ausercannowchangehishandleanynumberoftimes.Buteachnewhandlemustnotbeequaltoanyhandlethatisalreadyusedorthatwasusedatsomepoint.Mish......
  • 1163. 按字典序排在最后的子串
    题目链接:1163.按字典序排在最后的子串方法:双指针解题思路【正常走路我不走,就是跳,就是玩】任何非后缀子串字典序都小于其相应的后缀子串,如\(s[i,i+k]<s[i,n-1]\),\(k<n-1\),故答案一定为后缀子串,即\(s[i,n-1]\);观察数据规模,\(4*10^5\),暴力一定超时;法宝:......
  • pydictor —— 一个强大实用的黑客暴力破解字典建立工具
    pydictor下载环境kalihttps://github.com/LandGrey/pydictor/下载玩解压,然后在pydictor文件夹下打开终端即可。他可以帮助我们快速的生成普通爆破字典、基于网站内容的自定义字典、社会工程学字典等等一系列高级字典还可以使用内置工具,对字典进行安全删除、合并、去重、合并并......
  • 什么是字典?
    原文点此跳转什么是字典?与集合类似,字典也是一种存储唯一值的数据结构,但它是以键值对的形式来存储。在ES6中新增了Map字典。实现功能delete删除元素clear清空所有元素set添加/覆盖元素get查找/返回元素的值has判断是否包含某个元素应用场景两个数组的交集有效的括号两数之......
  • Hibernate关联关系映射
    1.  Hibernate关联关系映射1.1. onetoone<classname="Person"><idname="id"column="personId"><generatorclass="native"/></id><jointable="PersonAddress"......