-
康托展开
公式:X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! ,其中a[i]为当前未出现的元素中(即后面的所有元素中)是排在第几个(从0开始)。这就是康托展开。
代码:
//康拓展开
//给定一个字符串,按照字典序排序,算出这个字符串在哪个位置,注意此处排列从0开始
ll fac[21]; //到20的阶乘表,一般开longlong
ll cantor(char str[])
{
int len=strlen(str);
ll ans=0;
for(int i=0;i<len;i++)
{
ll tmp=0;
for(int j=i+1;j<len;j++)
{
if(str[j]<str[i])
tmp++;
}
ans+=tmp*fac[len-i-1];
}
return ans;
}
逆康拓展开:
//逆康拓展开
//给定n个元素的全排列,求第m大的全排列数是多少
//这里假设全排列还是从0开始排序
int ans[20]; //保存结果
ll fac[20]; //到20的阶乘表
void reverse_cantor(int n,int m)
{
m--; //因为康拓展卡是从0开始,而实际问题是从1开始,所以要--,若实际也从0开始,则不用减
int vis[20]={0}; //保存某个数被访问没
for(int i=n-1;i>=0;i--)
{
int tmp=m/fac[i];
int k=m%fac[i];
int cnt=0,j;
for(j=1;j<=n;j++)
{
if(vis[j]==0)
cnt++;
if(cnt==tmp+1) //第tmp+1小的数即为当前位
break;
}
ans[i]=j;
m=k;
vis[j]=1;
}
}