康托展开:对全排列的HASH和还原,判断搜索中的某个排列是否出现过

题目:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=2297

前置技能:(千万注意是从0开始数的

康托展开表示的是当前排列在n个不同元素的全排列中的名次。比如213在这3个数所有排列中排第3。

那么,对于n个数的排列,康托展开为:

其中表示第i个元素在未出现的元素中排列第几。举个简单的例子:

对于排列4213来说,4在4213中排第3,注意从0开始,2在213中排第1,1在13中排第0,3在3中排第0,即:

,这样得到4213在所有排列中排第ans=20

代码实现:(从0开始计数)

//康托展开  
LL Work(char str[])  
{  
    int len = strlen(str);  
    LL ans = 0;  
    for(int i=0; i<len; i++)  
    {  
        int tmp = 0;  
        for(int j=i+1; j<len; j++)  
            if(str[j] < str[i]) tmp++;  
        ans += tmp * f[len-i-1];  //f[]为阶乘  
    }  
    return ans;  //返回该字符串是全排列中第几大,从1开始  
}  

康托展开的逆运算:就是根据某个排列的在总的排列中的名次来确定这个排列。比如:

求1234所有排列中排第20的是啥,那么就利用辗转相除法确定康托展开中的系数,然后每次输出当前未出现过的第个元素。

代码实现康托展开逆运算:

//康托展开逆运算  
void Work(LL n,LL m)  
{  
    n--;  
    vector<int> v;  
    vector<int> a;  
    for(int i=1;i<=m;i++)  
        v.push_back(i);  
    for(int i=m;i>=1;i--)  
    {  
        LL r = n % f[i-1];  
        LL t = n / f[i-1];  
        n = r;  
        sort(v.begin(),v.end());  
        a.push_back(v[t]);  
        v.erase(v.begin()+t);  
    }  
    vector<int>::iterator it;  
    for(it = a.begin();it != a.end();it++)  
        cout<<*it;  
    cout<<endl;  
}  
时间: 2024-10-12 15:38:49

康托展开:对全排列的HASH和还原,判断搜索中的某个排列是否出现过的相关文章

Gym10081 A - Arcade Game -康托展开、全排列、组合数变成递推的思想

最近做到好多概率,组合数,全排列的题目,本咸鱼不会啊,我概率论都挂科了... 这个题学到了一个康托展开,有点用,瞎写一下... 康托展开: 适用对象:没有重复元素的全排列. 把一个整数X展开成如下形式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[2]*1!+a[1]*0![1] 其中a[i]为当前未出现的元素中是排在第几个(从0开始),并且0<=a[i]<i(1<=i<=n) 用来求全排列中这个串排第几,康托展开的逆运算就是

HDU ACM 1043 Eight-&gt;广度优先搜索(BFS)+康托展开(全排列hash)实践

分析:经典的八数码问题,参考别人的代码写的,逆向广搜,把结果保存起来,之后在使用. #include<iostream> #include<queue> using namespace std; #define STATE_COUNT 363000 //因为9!=362880 int fact[]={1,1,2,6,24,120,720,5040,40320,362880}; //0到9的阶乘,用来计算hash值 char dir[4][2]={ {0,1},{0,-1},{1,0

康托展开-全排列的编码与解码

一.康托展开:全排列到一个自然数的双射 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! ai为整数,并且0<=ai<i(1<=i<=n) 适用范围:没有重复元素的全排列 二.全排列的编码: {1,2,3,4,...,n}的排列总共有n!种,将它们从小到大排序,怎样知道其中一种排列是有序序列中的第几个? 如 {1,2,3} 按从小到大排列一共6个:123 132 213 231 312 321.想知道321是{1,2,3}中

全排列的编码与解码——康托展开

.康托展开:全排列到一个自然数的双射 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! ai为整数,并且0<=ai<i(1<=i<=n) 适用范围:没有重复元素的全排列 二.全排列的编码: {1,2,3,4,...,n}的排列总共有n!种,将它们从小到大排序,怎样知道其中一种排列是有序序列中的第几个? 如 {1,2,3} 按从小到大排列一共6个:123 132 213 231 312 321.想知道321是{1,2,3}中第

全排列和康托展开

一.康托展开:全排列到一个自然数的双射 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! ai为整数,并且0<=ai<i(1<=i<=n):其中X最常见的可以设为:0 <=X<=n!-1,第一个排列即123...n;该排列的X可设为0: 适用范围:没有重复元素的全排列 二.全排列的编码: {1,2,3,4,...,n}的排列总共有n!种,将它们从小到大排序,怎样知道其中一种排列是有序序列中的第几个? 如 {1,2

康托展开

对于n个数的全排列,共有n!中排列方式,如何求某一个序列在整个排列中的次序(从小到大)? 以9的全排列举例:842697513是1-9全排列的第几个?(高中数学排列组合问题,只需要做到不重不漏) 首先看第一位为8,那么第一位为1-7的全排列都比它小,共有7*8!个. 在第一位为8的情况下,其次看第二位为4,那么第二位为1-3的全排列都比它小,共有1*3*7!个. 在第一位为8,第二位为4的情况下,那么第三位为1的全排列都比它小,共有1*1*6!个. 在第一位为8,第二位为4,第三位为2的情况下,

Feed Ratios(康托展开 )

Magic SquaresIOI'96 Following the success of the magic cube, Mr. Rubik invented its planar version, called magic squares. This is a sheet composed of 8 equal-sized squares: 1 2 3 4 8 7 6 5 In this task we consider the version where each square has a

浅谈康托展开和其逆运算

康托展开,是一种在\(\mathcal{O}(n^2)\)(\(n\)为排列元素个数)时间复杂度求解某一排列在全排列中的次序的算法. 我们以一道例题引入: 排列的序号 题目描述: 给定一个数\(n\)和一个\(n\)个数的排列\(a\),求\(a\)在\(n\)的全排列中的序号. 输入描述: 第一行一个整数\(n\),第二行一个排列\(a\). 输出描述: 求\(a\)在\(n\)的全排列中的序号. 输入输出样例: 输入 3 123 输出 1 数据范围 \(n\le 15\) 根据排列组合.加法

【康托展开】

康托展开: 1.定义:给一个n个不同数字的排列,求所有排列中比该排列要小的个数X 2.式子:$X=a_n*(n-1)!+a_{n-1}*(n-2)!+……+a_1*0!$,其中$a_i$表示第1位到第i-1位上的数字中,比第i位(从右往左数)数字的个数小的数量. 3.例子:如 {1.2.3.4}的一个排列 {2.1.4.3}: X=1*3!+0*2!+1*1!+0*1!= 7. 逆康托展开 1.猜想:既然我们可以通过1-n的一个排列S,求出X(S),那么是否给定一个X(S)可以求出S呢? 2.结