康拓展开

康托展开是什么?

定义:

X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!

ai为整数,并且0<=ai<i(1<=i<=n)

简单点说就是,判断这个数在其各个数字全排列中从小到大排第几位。

比如 132,在1、2、3的全排列中排第2位。


康托展开有啥用呢?

维基:n位(0~n-1)全排列后,其康托展开唯一且最大约为n!,因此可以由更小的空间来储存这些排列。由公式可将X逆推出对应的全排列。

它可以应用于哈希表中空间压缩,

而且在搜索某些类型题时,将VIS数组量压缩。比如:八数码魔板。。


康托展开求法:

比如2143 这个数,求其展开:

从头判断,至尾结束,

① 比 2(第一位数)小的数有多少个->1个就是1,1*3!

② 比 1(第二位数)小的数有多少个->0个0*2!

③ 比 4(第三位数)小的数有多少个->3个就是1,2,3,但是1,2之前已经出现,所以是  1*1!

将所有乘积相加=7

比该数小的数有7个,所以该数排第8的位置。

1234  1243  1324  1342  1423  1432
2134  2143  2314  2341  2413  2431
3124  3142  3214  3241  3412  3421
4123  4132  4213  4231  4312  4321


康拓展开的代码:

int fac[10]={1,1,2,6,24,120,720,5040,40320,362880};
// 康拓展开 是将全排列转会为数字,压缩空间; 
int kangtuo(int n,char str[])  //n为全排列字符的长度,str[] 为这个的全排列 
{
	int i,j;                 //全排列 我这个康拓返回的是1~fac[n],因return的是sum+1 
	int t,sum = 0;
	for(i=0;i<n;i++)
	{
		t = 0;        //后面比它小的个数; 
		for(j = i+1;j<n;j++)
			if(str[i]>str[j])
				t++;
		sum +=t*fac[n-i-1]; //fac[k], k为第i位后面还有多少位; 
	}
	return sum+1;
}


康托展开的逆:

康托展开是一个全排列到自然数的双射,可以作为哈希函数。

所以当然也可以求逆运算了。

逆运算的方法:

假设求4位数中第19个位置的数字。

① 19减去1  → 18

② 18 对3!作除法 → 得3余0

③  0对2!作除法 → 得0余0

④  0对1!作除法 → 得0余0

据上面的可知:

我们第一位数(最左面的数),比第一位数小的数有3个,显然 第一位数为→ 4

比第二位数小的数字有0个,所以 第二位数为→1

比第三位数小的数字有0个,因为1已经用过,所以第三位数为→2

第四位数剩下 3

该数字为  4123  (正解)


代码:

int fac[10]={1,1,2,6,24,120,720,5040,40320,362880};
//康拓展开的逆运算,把一个数 转化为 全排列,n为全排列的长度,str[] 要存全排列的数组,num为要转化的数;
void re_kangtuo(int n,char str[],int num)   
{
	int i,j,t,book[10] = {0};
	num--;                  // 因我康拓时,返回的是sum+1;
	for(i=0;i<n;i++)        //一定要先算最左边一位,依次类推; 
	{
		t = num/fac[n-i-1];   
		for(j = 1;j<=n;j++)
		{
			if(!book[j])
			{
				if(t==0) break;
				t--;       // 第i位后有几位小于自身的; 
			}
		}
		
		str[i] = j+'0';
		book[j] = 1;    //把找到的数标记了
		num = num%fac[n-i-1];
	}
	str[n] = '\0';	
} 





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值