P1092全排列

https://vijos.org/p/1092

描述
输入两个自然数m,n 1<=n<=20,1<=m<=n!
输出n个数的第m种全排列。

如 :
输入 3 1
输出 1 2 3

格式
输入格式
在一行中输入n m

输出格式
一个数列,既n个数的第m种排列
每两个数之间空1格

样例1
样例输入1[复制] 3 2
样例输出1[复制] 1 3 2
code :

// 主要是用康托展开式逆运算算法
#include  <iostream>
#include  <string>
using namespace std;
const int PermSize = 21;
//将20进制的数全不打印出来
__int64 factory[PermSize] = { 0,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800,87178291200,1307674368000,20922789888000,355687428096000,6402373705728000,121645100408832000,2432902008176640000};
void Uncantor(int n, int k)  
{  
    int i, j, vst[30]={0},s[30]; 
	int  t;
       k--;  
	  //vst 用来标记
    for (i=0; i<n; i++)  
    {  
	     
	    if(k==0 || factory[n-i-1]==0)  // 当其中一个为0是以是最后一次进行操作
			t=0;
		else
		{
            t = k/factory[n-i-1]; //  0/0 会出现编译出错
          	k %= factory[n-i-1];  
		}
	   for (j=1; j<=n; j++)  
            if (!vst[j])  //如果存在就要往后移
            {  
                if (t == 0) break;  
                t--;  
            }  
         s[i] = j;  
        vst[j] = 1;  
      
    }  
	for(i=0;i<n-1;i++)
		cout<<s[i]<<" ";
	cout<<s[i]<<endl;
}  
int main()
{
	int n,m;
    while(cin>>n>>m)
	{
		Uncantor(n,m);
	
	}
	
	return 0;
}


 

康托展开的逆运算:

 

{1,2,3,4,5}的全排列已经从小到大排序,要找出第16个数:

1. 首先用16-1得到15

2. 用15去除4! 得到0余15

3. 用15去除3! 得到2余3

4. 用3去除2! 得到1余1

5. 用1去除1! 得到1余0

有0个数比它小的数是1

所以第一位是1

有2个数比它小的数是3,但1已经在之前出现过了所以是4

有1个数比它小的数是2,但1已经在之前出现过了所以是3

有1个数比它小的数是2,但1,3,4都出现过了所以是5

最后一个数只能是2

所以这个数是14352

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值