OJ 1188 全排列---康托展开
题目描述
求n的从小到大第m个全排列(n≤20)。
输入
n和m
输出
输出第m个全排列,两个数之间有一空格。
样例输入
样例输出
#include<cstdio>
#include<cstring>
const long long fac[] = {,,,,,,,,,,
,,,,
,,,
,,,
}; bool vis[];
void invKT(int ans[], int n, int k)
{
int i, j, t;
memset(vis, , sizeof(vis));
k--;
for (i=; i< n;++i)
{
t=k /fac[n- i-];
for (j=; j<= n; j++)
if (!vis[j])
{
if (t == ) break;
t--;
}
ans[i] = j, vis[j] = true;
k %= fac[n - i - ];
}
} int main()
{
int a[],n;
long m;
while(scanf("%d%ld",&n,&m)!=EOF)
{
invKT(a,n,m);
for (int i = ; i <n;i++)
printf("%d ",a[i]);
printf("\n");
}
return ;
}
/**************************************************************
Problem: 1188
User: 2014217052
Language: C++
Result: 正确
Time:3 ms
Memory:1032 kb
****************************************************************/
时间用的还是有点多,据说加上递归会快。
还是要总结一下康托展开,以后用的方便些。
全排列的编码与解码——康托展开
一、康托展开:全排列到一个自然数的双射
X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!
ai为整数,0<=ai<i(1<=i<=n)
适用范围:没有重复元素的全排列(*注:注意应用范围)
二、全排列的编码:
{1,2,3,4,...,n}的排列总共有n!种,将它们从小到大排序,怎样知道其中一种排列是有序序列中的第几个?
如 {1,2,3} 按从小到大排列一共6个:123 132 213 231 312 321。想知道321是{1,2,3}中第几个大的数。
这样考虑:第一位是3,小于3的数有1、2 。所以有2*2!个。再看小于第二位,小于2的数只有一个就是1 ,所以有1*1!=1 所以小于32
的{1,2,3}排列数有2*2!+1*1!=5个。所以321是第6个大的数。2*2!+1*1!是康托展开。(注意判断排列是第几个时要在康托展开的结果后+1)
再举个例子:1324是{1,2,3,4}排列数中第几个大的数:
第一位是1小于1的数没有,是0个,0*3!,第二位是3小于3的数有1和2,但1已经在第一位了,所以只有一个数2,1*2! 。
第三位是2小于2的数是1,但1在第一位,所以有0个数,0*1!,所以比1324小的排列有0*3!+1*2!+0*1!=2个,1324是第三个大数。
又例如,排列3 5 7 4 1 2 9 6 8展开为98884,因为X=2*8!+3*7!+4*6!+2*5!+0*4!+0*3!+2*2!+0*1!+0*0!=98884.
解释:
排列的第一位是3,比3小的数有两个,以这样的数开始的排列有8!个,因此第一项为2*8!
排列的第二位是5,比5小的数有1、2、3、4,由于3已经出现,因此共有3个比5小的数,这样的排列有7!个,因此第二项为3*7!
以此类推,直至0*0!
代码:
#include<cstdio> const int fac[] = {, , , , , , , , };///阶乘 int KT(int s[], int n) { int i, j, cnt, sum; sum = ; for (i = ; i < n; ++i) { cnt = ; for (j = i + ; j < n; ++j) if (s[j] < s[i]) ++cnt; sum += cnt * fac[n - i - ]; } return sum; } int main() { int a[] = {, , , , , , , , }; printf("%d\n", + KT(a, sizeof(a) / sizeof(*a))); ///1+98884 }
三、全排列的解码
如何找出第16个(按字典序的){1,2,3,4,5}的全排列?
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
所以排列为1 4 3 5 2
#include<cstdio> #include<cstring> const int fac[] = {, , , , , , , , };///阶乘 bool vis[]; ///n为ans大小,k为全排列的编码 void invKT(int ans[], int n, int k) { int i, j, t; memset(vis, , sizeof(vis)); --k; for (i = ; i < n; ++i) { t = k / fac[n - i - ]; for (j = ; j <= n; j++) if (!vis[j]) { if (t == ) break; --t; } ans[i] = j, vis[j] = true; k %= fac[n - i - ];///余数 } } int main() { int a[]; invKT(a, , ); for (int i = ; i < ; ++i) printf("%d ", a[i]);///1 4 3 5 2 }
OJ 1188 全排列---康托展开的更多相关文章
- 用康托展开实现全排列(STL、itertools)
康拓展开: $X=a_n*(n-1)!+a_{n-1}*(n-2)!+\ldots +a_2*1!+a_1*0!$ X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+ ...
- LightOJ1060 nth Permutation(不重复全排列+逆康托展开)
一年多前遇到差不多的题目http://acm.fafu.edu.cn/problem.php?id=1427. 一开始我还用搜索..后来那时意外找到一个不重复全排列的计算公式:M!/(N1!*N2!* ...
- 康托展开:对全排列的HASH和还原,判断搜索中的某个排列是否出现过
题目:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=2297 前置技能:(千万注意是 ...
- HDU 1043 Eight 【经典八数码输出路径/BFS/A*/康托展开】
本题有写法好几个写法,但主要思路是BFS: No.1 采用双向宽搜,分别从起始态和结束态进行宽搜,暴力判重.如果只进行单向会超时. No.2 采用hash进行判重,宽搜采用单向就可以AC. No.3 ...
- UVA11525 Permutation[康托展开 树状数组求第k小值]
UVA - 11525 Permutation 题意:输出1~n的所有排列,字典序大小第∑k1Si∗(K−i)!个 学了好多知识 1.康托展开 X=a[n]*(n-1)!+a[n-1]*(n-2)!+ ...
- leetcode 60. Permutation Sequence(康托展开)
描述: The set [1,2,3,…,n] contains a total of n! unique permutations. By listing and labeling all of t ...
- NYOJ--139--我排第几个(康托展开)
我排第几个 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 现在有"abcdefghijkl"12个字符,将其所有的排列中按字典序排列,给出任意一 ...
- 康托展开&&康托逆展开
康托展开 简介:对于给定的一个排列,求它是第几个,比如54321是n=5时的第120个.(对于不是1~n的排列可以离散化理解) 做法: ans=a[n]*(n-1)!+a[n-1]*(n-2)!+~~ ...
- [洛谷P3014][USACO11FEB]牛线Cow Line (康托展开)(数论)
如果在阅读本文之前对于康托展开没有了解的同学请戳一下这里: 简陋的博客 百度百科 题目描述 N(1<=N<=20)头牛,编号为1...N,正在与FJ玩一个疯狂的游戏.奶牛会排成一行 ...
随机推荐
- 第九章:Javascript类和模块
(过年了,祝大家新年好!) 第6章详细介绍了javascript对象,每个javascript对象都是一个属性集合,相互之间没有任何联系.在javascript中也可以定义对象的类,让每个对象都共享某 ...
- Xamarin.Forms入门学习路线
Xamarin 介绍 Xamarin是一套跨平台解决方案,目的是使用C#语言创造原生的iOS,Android,Mac和Windows应用. Xamarin的三个优势: Xamarin App拥有原生A ...
- Sublime Text 3 Build 3065 All System CracKed By Hmily[LCG]
Sublime Text 3 Build 3065 All System CracKed By Hmily[LCG] <ignore_js_op> 程序员文本编辑器 Sublime Tex ...
- [转]java基础学习总结——equals方法
一.equals方法介绍 1.1.通过下面的例子掌握equals的用法 1 package cn.galc.test; 2 3 public class TestEquals { 4 public s ...
- Spring 作用域 scope
spring的作用域将对Bean的生命周期和创建方式产生影响. 主要分为五种类型的作用域 singleton (默认)在spring IOC容器中仅存在一个Bean实例,Bean以单实例的方式存在. ...
- 【HDU 5115】Dire Wolf
题意 n只狼排成一行,每次击败第i只狼需要ai+bi-1+bi+1代价,击败后,相当于出列了,与i相邻两只狼成了相邻的.求击败所有狼的最小总代价. 分析 我开始一直以为是个环TAT.. 区间dp,dp ...
- 【POJ 1416】Shredding Company
题 题意 给你一个target number,和一个最多六位的数num,让你把数分段,使总和最接近但不大于target number. 如果只有一种方法就输出总和.分段,如果有多种方法,输出rejec ...
- 【bzoj1202】 HNOI2005—狡猾的商人
http://www.lydsy.com/JudgeOnline/problem.php?id=1202 (题目链接) 题意 给出m段区间和,判断是否存在某段区间与之前读入的区间相矛盾. Soluti ...
- Linux Cache Mechanism Summary(undone)
目录 . 缓存机制简介 . 内核缓存机制 . 内存缓存机制 . 文件缓存机制 . 数据库缓存机制 1. 缓存机制简介 0x1: 什么是缓存cache 在计算机整个领域中,缓存(cache)这个词是一个 ...
- 项目总结—jQuery EasyUI- DataGrid使用
http://blog.csdn.net/zwk626542417/article/details/18839349 概要 jQuery EasyUI是一个基于jquery的集成了各种用户界面的框架, ...