康拓展开
把一个整数X展开成如下形式:
X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[2]*1!+a[1]*0!
其中a[i]为''当前元素''在''所有未出现的元素''中排在第i个(从0开始),并且0<=a[i]<i(1<=i<=n)
为了更好的理解康托展开,举个例子
序列
3 4 6 2 1 7 5 8 0
总共有9个数
第一个数3在未出现的数字排第四 3*(8!)
a[n]即在它之后有多少个比它小,阶乘的阶数从最大的数开始
这样就可以一个一个算出来了
代码实现
int work()
{
int code=0;
for(int i=0;i<9;i++)
{
int cnt=0;
for(int j=i+1;j<9;j++)
if(st[i]<st[j]) cnt++;
code +=fact[8-i]*cnt;
}
return code;
}
康拓逆展开
这个百度百科写的挺好的直接照抄了
例1 {1,2,3,4,5}的全排列,并且已经从小到大排序完毕
(1)找出第96个数
首先用96-1得到95
用95去除4! 得到3余23
有3个数比它小的数是4
所以第一位是4
用23去除3! 得到3余5
有3个数比它小的数是4但4已经在之前出现过了所以第二位是5(4在之前出现过,所以实际比5小的数是3个)
用5去除2!得到2余1
有2个数比它小的数是3,第三位是3
用1去除1!得到1余0
有1个数比它小的数是2,第二位是2
最后一个数只能是1
所以这个数是45321
代码:
void invkt(int k,int *s)
{
memset(vis2,0,sizeof(vis2));
for(int i=0;i<9;i++)
{
int t=k/fac[8-i];
int j;
for( j=0;j<9;j++)
{
if(!vis2[j])
{
if(t==0)
break;
t--;
}
}
s[i]=j;
vis2[j]=true;
k%=fac[8-i];
}
}