康托展开应用于全排列模型的问题,可以用康托展开来求一个排列在全排列中是排第几个的,可以说是一种状态压缩,这样我们就直到这个排列的状态了
每种排序都会产生一个独一无二的序列号:
我们用a[i]表示:在当前尚未出现的数字中,a[i]是第几大的数字,也就是说从第i位开始到最后,比第i位小的数有几个(1<=i<=n)从左往右计算:
C=a[1]*(n-1)!+a[2]*(n-2)!+...+a[i]*(n-i)!+...+a[n-1]*1!+a[n]*0!
比如在1-4的全排列中,3421是第几大的:
C=2*3!+2*2!+1*1!+1*0!=17
也可以把一个数字转换成一个数组表示这个数字对应的状态
void Countor(int s[],ll num,int n)//康托正展开,将一个数(状态)展开成一个数组,n是数组长度
{//注意这里是从0开始存储的,s[0]存储的是最小的排列状态
ll t;
bool flag[n];
memset(flag,0,sizeof(flag));
for(int i=0;i<n;i++)
{
t=num/fac[n-i-1];
num=num%fac[n-i-1];
for(int j=0,pos=0;;j++,pos++)
{
if(flag[pos])
{
j--;
}
if(j==t)
{
flag[pos]=true;
s[i]=pos+1;
break;
}
}
}
}
ll coutor(int str[],int n)//康托逆展开,将一个数组s换算成一个数字
{
ll res=0;
for(int i=0;i<n;i++)
{
int cnt=0;
for(int j=i+1;j<n;j++)
{
if(c[i]>c[j])
{
cnt++;
}
}
res+=(cnt*fac[n-i-1]);
}
return (res+1);
}