可以用于求排列的第几大。如要求{1,3,2}在排列{1,2,3}中是第几大时可以用康拓展开来求
这个博客里面讲得很清楚:
#include<iostream>
#include<string>
using namespace std;
long fac[13];
int an(const string & s,int n) //求下标为n的字符在子数组中第几大,从0开始数
{
int result = 0,i;
for (i=n+1;i<s.length();i++)
if (s[n]>s[i])
result++;
return result;
}
void Factorial() //计算阶乘
{
fac[0] = 1;
int i;
for (i=1;i<13;i++)
fac[i] =fac[i-1]*i;
}
long X(const string & s)//求康托展开的X值
{
long result = 0;
int len = s.length();
int i;
for (i=0;i<len;i++)
{
result += an(s,i)*fac[len-i-1];
}
return result;
}
/*测试*/
int main()
{
string s = "ABC";
string s1 = "ACB";
Factorial();
cout<<X(s)<<endl;
cout<<X(s1)<<endl;
return 0;
}
逆康拓展开,用于求第几个排列
/*逆康拓展开*/
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
long fac[13];
void Factorial() //计算阶乘
{
fac[0] = 1;
int i;
for (i=1;i<13;i++)
fac[i] =fac[i-1]*i;
}
int Ai(int an,int n,char sub[])//用于求第an大的字符
{
int r=-1,i;
for (i=0;i<n;i++)
{
if (sub[i]!='\0')
r++;
if (r==an)
return i;
}
}
/*s用于存放原始的排列(如{1,2,3}),m为所需求的第几个排列(从0开始)*/
char * Permutation(char s[],int m)
{
char *sub = new char[strlen(s)]; //用于标记哪个字符有用过或没用过
char *result = new char[strlen(s)]; //用于存放所求排列结果
strcpy(sub,s);
int i,j;
for (j=0,i=strlen(s)-1;i>=0;i--,j++)
{
int an = Ai(m/fac[i],strlen(s),sub);
result[j] = sub[an];
m = m%fac[i];
sub[an] = '\0'; //删去,表示已经用了
}
return result;
}
/*测试*/
int main()
{
Factorial();
char s[] = "abcdef";
char *c = Permutation(s,1);
int i;
for (i=0;i<strlen(s);i++)
putchar(c[i]);
putchar('\n');
free(c);
return 0;
}