HDOJ 1027 Ignatius and the Princess II
题目
分类
组合数学 康托展开
其他解法 搜索
STL 全排列
题意
英雄 Ignatius 救 公主 的故事背景
本题是第二部分
求 n 个数的第 m 个排列例如
4 个 数的序列
第 1 个(从1 开始) 1 2 3 4
第 4 个 (从1 开始 ) 1 3 4 2
题解
如果逐个搜索非常慢
我们还是 用 康托展开 效率较高
当然直接用 STL 模板全排列也可以康托展开
把一个整数X展开成如下形式:
X=a[n](n-1)!+a[n-1](n-2)!+…+a[i]*(i-1)!+…+a[1]*0!
其中a[i]为当前未出现的元素中是排在第几个(从0开始),并且0<=a[i](1<=i<=n)
例如 1 3 4 2
未选序列 当前数字 已选序列 康托展开式 1 2 3 4 1 - 2 3 4 3 1 0 * 3! 2 4 4 1 3 0 * 3! + 1 * 2! 2 2 1 3 4 0 * 3! + 1 * 2! + 1 * 1! - - 1 3 4 2 0 * 3! + 1 * 2! + 1 * 1! + 0 * 0! 下面给出更详细的解释
第一行 1 3 4 2 的第一个数为 1 在 1 2 3 4 中在 第0位(从0开始) 所以康托展开位 0 * (4 - 1)!
第二行 1已被选出 序列 3 4 2的第一个数 3 在 2 3 4 的 第1位 所以 康托展开式位 0 * (4 - 1)!
+ 1 * (4 - 2)!
依次类推 4个数的 第3个排列 (从0 开始) 1 3 4 2 的 康托展开为 0 * 3! + 1 * 2! + 1 * 1! + 0 * 0!本题是求第几个排列,所以 只要逆康托展开即可
例如 4个数的 第3个排列(从0 开始) 的计算
3 / 3! = 0, 3 % 3! = 3 所以 第1位为 1 2 3 4 中的 第 0 个 1
用上一步余数继续
3 / 2! = 1, 3 % 2! = 1 所以 第2位为 2 3 4 中的 第 1 个 3
1 / 1! = 1, 3 % 1! = 0 所以 第2位为 2 4 中的 第 1 个 4
0 / 0! = 1, 0 % 0! = 0 所以 第2位为 2 中的 第 0 个 2
代码 (STL 全排列方法)
有写好的就不重复劳动了
点击查看 STL 全排列方法
代码 (康托展开法)
#include <iostream>
#define max 9
using namespace std;
int fac[max] = {1,1,2,6,24,120,720,5040,40320};
int main()
{
int n,m,f,d,t,z;
while(cin >> n >> m)
{
m --;
if(m != 0)
for(f = max - 1;f >= 0 && m / fac[f] == 0;f--)
;
else f = 0;
for(int i = 1;i < n-f;i++)
cout << i << " ";
d = 0;
for(int i = f;i >= 0;i--)
{
// cout << " i " << i << endl;
z = -1;
t = m / fac[i];
// cout << "t " << t << endl;
for(int j = 0;j <= f;j++)
{
// cout << "d " << d << endl;
if(!(d & (1 << j)))
z++;
if(z == t)
{
if(d != 0)
cout << " ";
cout << n - f + j;
d |= (1 << j);
break;
}
}
m %= fac[i];
}
cout << endl;
}
return 0;
}