康托展开和逆康托展开

康托展开:已知一个排列,求这个排列在全排列中是第几个。。。

康托展开逆运算:已知在全排列中排第几,求这个排列。。。

 康托展开:

对于{1,2,3,...,n}生成的已经从小到大排序好的全排列
x=a[n]*(n-1)!+a[n-1]*(n-2)!+...a[1]*0!

  • a[i] 指的是位于位置i后面的数小于a[i]值的个数,后面乘的就是后面还有多少个数的阶乘

  • 说明 :这个算出来的数康拖展开值,是在所有排列次序 - 1的值,因此x+1即为在全排列中的次序

 

在(1,2,3,4,5)5个数的排列组合中,计算 34152的康托展开值。
带入上面的公式

  • x = 2 * 4! + 2 * 3! + 0 * 2! + 1 * 1! + 0 * 0!(3后面有两个比他小的,4有两个,1没有……依次类推)
    =>x = 61

逆康托展开: 

在(1,2,3,4,5) 给出61可以算出起排列组合为34152
具体过程如下:
用 61 / 4! = 2余13,说明 ,说明比首位小的数有2个,所以首位为3。
用 13 / 3! = 2余1,说明 ,说明在第二位之后小于第二位的数有2个,所以第二位为4。
用 1 / 2! = 0余1,说明 ,说明在第三位之后没有小于第三位的数,所以第三位为1。
用 1 / 1! = 1余0,说明 ,说明在第二位之后小于第四位的数有1个,所以第四位为5。

#include <bits/stdc++.h>
#define ll long long 
using namespace std;
static const ll Fac[]={1,1,2,6,24,120,720,5040,40320,362880,39916800,479001600,6227020800,87178291200,1307674368000,20922789888000,355687428096000,6402373705728000};
//阶乘 
//康托展开 
ll cantor(ll *a,ll n)
{
	ll x=0;
	for(int i=0;i<n;i++)
	{
		int smaller=0;//在当前位之后小于其的个数 
		for(int j=i+1;j<n;j++)
		{
			if(a[j]<a[i])
			{
				smaller++;
			}
		 } 
		x+=Fac[n-i-1]*smaller;//康托展开累加 
	}
	return x;
 } 
 
/*康托展开逆运算*/
/*n代表待查找的数排列在第几位*/
/*1.2.3.4.5...m*/ 
void decantor(ll n,ll m)
{
	n--;//减一之后再是 康托展开的值 
	vector <int> v;//存放当前可选数
	vector <int> a;//所求的排列组合
	for(int i=1;i<=m;i++)
		v.push_back(i);
	for(int i=m;i>=1;i--)
	{
		ll r=n%Fac[i-1];
		ll t=n/Fac[i-1];
		n=r;
		sort(v.begin(),v.end());//从小到大排序
		a.push_back(v[t]);//剩余数里第t+1个数为当前位
		v.erase(v.begin()+t);//移除选做当前位的数 
	 } 
	 vector <int>::iterator it;
	 for(it=a.begin();it!=a.end();it++)
	 	cout<<(*it);
	cout<<endl; 
}
int main()
{
	ll a[5]={3,4,1,5,2};//计算34152的康托展开值
	cout<<"34152的康托展开值:"<<cantor(a,5)<<endl;
	cout<<"34152排列在第"<< cantor(a,5)+1<<"位"<<endl;
	cout<<"逆运用:(在1.2.3..m下第62位排列数是)"<<endl;	
	decantor(62,5);
	
	/*全排列问题*/
	int n,k;
	cin>>n>>k;/*(1...n)所有排列中,升序排在第k位的是?*/
	decantor(k,n);
	return 0;
}


 

蓝桥杯,康拓展开模板题;

问题
X星系的某次考古活动发现了史前智能痕迹。 
这是一些用来计数的符号,经过分析它的计数规律如下: 
(为了表示方便,我们把这些奇怪的符号用a~q代替)

abcdefghijklmnopq 表示0 
abcdefghijklmnoqp 表示1 
abcdefghijklmnpoq 表示2 
abcdefghijklmnpqo 表示3 
abcdefghijklmnqop 表示4 
abcdefghijklmnqpo 表示5 
abcdefghijklmonpq 表示6 
abcdefghijklmonqp 表示7 
…..

在一处石头上刻的符号是:

bckfqlajhemgiodnp

请你计算出它表示的数字是多少?

请提交该整数,不要填写任何多余的内容,比如说明或注释。
 

 答案:22952601027516

#include <bits/stdc++.h>
#define ll long long 
using namespace std;
ll Fac[20];
//阶乘 
void init()
{
	Fac[0]=1;
	Fac[1]=1;
	for(int i=2;i<18;i++)
	{
		Fac[i]=i*Fac[i-1]; 
	}
}

//康托展开 
ll cantor(char a[],ll n)
{
	ll x=0;
	for(int i=0;i<n;i++)
	{
		int smaller=0;//在当前位之后小于其的个数 
		for(int j=i+1;j<n;j++)
		{
			if(a[j]<a[i])
			{
				smaller++;
			}
		 } 
		x+=Fac[n-i-1]*smaller;//康托展开累加 
	}
	return x;
 } 
 
/*康托展开逆运算*/
/*n代表待查找的数排列在第几位*/
/*1.2.3.4.5...m*/ 
void decantor(ll n,ll m)
{
	n--;//减一之后再是 康托展开的值 
	vector <int> v;//存放当前可选数
	vector <int> a;//所求的排列组合
	for(int i=1;i<=m;i++)
		v.push_back(i);
	for(int i=m;i>=1;i--)
	{
		ll r=n%Fac[i-1];
		ll t=n/Fac[i-1];
		n=r;
		sort(v.begin(),v.end());//从小到大排序
		a.push_back(v[t]);//剩余数里第t+1个数为当前位
		v.erase(v.begin()+t);//移除选做当前位的数 
	 } 
	 vector <int>::iterator it;
	 for(it=a.begin();it!=a.end();it++)
	 	cout<<(*it);
	cout<<endl; 
}
int main()
{
	init();
	char s[]="bckfqlajhemgiodnp";
	//因为排序从0开始所有康托展开的值不需要加1 
	cout<< cantor(s,17)<<endl;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值