康托展开

关于康托展开的简单学习(小白的第一篇)

首先关于,康拓展开,我们要知道,这个关于全排列的一个用法。相信,我们在以后的算法学习中,会有所运用。
举例:
首先,我们要知道,对于(1,2,3)的全排列,有这几种,分别是,(1,2,3)、(1,3,2)、(2,1,3)、(2,3,1)、(3,1,2)、(3,2 ,1)这个顺序是根据字典序排列的。假如我们想知道它全排列的(2,3,1)是第几项,我们除了全部列出来,我们还可以通过康托展开知道。
首先它的公式是这样的:
X = A[0] * (n-1)! + A[1] * (n-2)! + … + A[n-1] * 0!

  1. A[i] 是当前i的逆序数(就是后面比它小的个数)
  2. 假如是(2,3,1)对因的A序列就是(1,1,0)
    那么这个结果就是,12!+11!+0*0!=3,这个和我们算的不符!
  3. 原因是,这个算出来的是,全排列减一的值,不信的计算一下(1,2,3)是不是0,所以,**我们的计算结果要+1!**那么结果就是4喽

接着,我们有康托展开式,就会有逆展开式,知道数字,就对应的展开式,嘿嘿!
假如我们知道它是4,且知道它是(123)(n=3),我们就可以通过取余,得到结果,1. 4/2! = 1(逆序数)。。。。。1 (下一次计算的值) 则此时可知为2,因为逆序数为1,此时只有2满足。
4. 1/1! = 1。。。。。0 此时可知是3,因为逆序数是1,也只有3满足。
5. 之后,就之后1了。
关于代码,我尝试写了写,不专业哦!

int ktzk (int a[],int n) {
	int ans =0;
	for (int i=0;i<n;i++) {
		int x=0;
		int c=1,m=1;
		for (int j=i+1;j<n;j++) {
			if (a[j]<a[i]) x++;
			m=m*c;
			c++;
			//这里通过算逆序数的过程,顺便算了,阶乘! 
		}
		and += x*m;
	}
	return ans; 
}
static const int FAC[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};   // 阶乘
  
//康托展开逆运算
void decantor(int x, int n)
{
    vector<int> v;  // 存放当前可选数
    vector<int> a;  // 所求排列组合
    for(int i=1;i<=n;i++)
        v.push_back(i);
    for(int i=m;i>=1;i--)
    {
        int r = x % FAC[i-1];
        int t = x / FAC[i-1];
        x = r;
        sort(v.begin(),v.end());// 从小到大排序
        a.push_back(v[t]);      // 剩余数里第t+1个数为当前位
        v.erase(v.begin()+t);   // 移除选做当前位的数
    }
}

//这个代码是大佬写的,我逆展开,真的写的没这么好!
我直接把大佬的链接发出来,果然还是要看看牛人的博客!
大佬的博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值