您的位置:首页 > 其它

康托展开

2017-11-24 10:23 176 查看
康托展开算法这里的知识点有两个,一个是给你一个a[]的全排列之一s,让你判断这个s在a的全排列中从小到大或者从大到小排第几,另一个是叫做康托展开的逆运算,也就是给你一个a[],再给你一个位置Pos,让你判断在pos位置的排列是什么输出来。

【1】康托展开求法:

从小到大:

比如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

用程序来实现就是:

#include<cstdio>
#include<algorithm>

4000
#include<iostream>
#include<cstring>
using namespace std;
int  fac[] = {1,1,2,6,24,120,720,5040,40320}; //i的阶乘为fac[i]
// 康托展开-> 表示数字a是 a的全排列中从小到大排,排第几
// n表示1~n个数  a数组表示数字。
int kangtuo(int n,char a[])
{
int i,j,t,sum;
sum=0;
for( i=0; i<n ;++i)
{
t=0;
for(j=i+1;j<n;++j)
if( a[i]>a[j] )
++t;
sum+=t*fac[n-i-1];
}
return sum+1;
}
int main()
{
int n;

char a[100];
scanf("%d",&n);
scanf("%s",&a);
cout<<kangtuo(n,a)<<endl;
}


从大到小:



代码

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
int  fac[] = {1,1,2,6,24,120,720,5040,40320}; //i的阶乘为fac[i]
// 康托展开-> 表示数字a是 a的全排列中从小到大排,排第几
// n表示1~n个数  a数组表示数字。
int kangtuo(int n,char a[])
{
int i,j,t,sum;
sum=0;
for( i=0; i<n ;++i)
{
t=0;
for(j=i;j<n;++j)
if( a[j]>a[i] )    //只有这里跟从小到大不一样;
++t;
sum+=t*fac[n-i-1];
}
return sum+1;
}
int main()
{
int n;

char a[100];
scanf("%d",&n);
scanf("%s",&a);
cout<<kangtuo(n,a)<<endl;
}


康托展开的逆运算:

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

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

逆运算的方法:

假设求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 (正解)

代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int fac[]={1,1,2,6,24,120,720,5040,40320};
int vis[8]={0};
void reverse_kangtuo(int n,int k,char s[])
{
int i,j;
k--;
for(i=0;i<n;i++)
{
int t=k/fac[n-i-1];
for(j=1;j<=n;j++)
{
if(!vis[j])
{
if(t==0)  break;
t--;
}
}
vis[j]=1;
s[i]=j+'0';
k=k%fac[n-i-1];
}
printf("%s\n",s);
}

int main()
{
int n,k;
char s[100];
memset(s,'\0',sizeof(s));
scanf("%d%d",&n,&k);
reverse_kangtuo(n,k,s);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法