(7.15)康托展开,就是把全排列转化为唯一对应自然数的算法。它可以建立1 ~ n的全排列与[1, n!]之间的自然数的双向映射。

1、康托展开:

  尽管我并不清楚康托展开的原理何在,这个算法的过程还是比较好记的。正确性之后有机会询问下学长。

  如果从1开始给全排列的排名从大到小编号的话(从0开始也可,建立的是与[0, n!-1]的映射,本质相同),定义rk为排名,a是排列数组,排列有n位(最低位是第0位),那么有公式

  rk - 1 = cnt[n-1] * (n-1)! + cnt[n-2] * (n-2)! + ... + cnt[0] * 0!  

  其中cnt数组的含义是未统计的数字中,小于a[i]的数字有多少个。

  举例:计算排列3 4 2 1对于{1, 2, 3, 4}的排名

  首先取出最高位(第三位),小于数字3的数有两个,所以cnt[3] = 2,rk += 2 * 3!,rk = 12。

  然后取出4,小于4的数有三个,但是3已经被统计过了,所以cnt[2] = 2,rk += 2 * 2!,rk = 16.

  取出2,小于2的只有1,cnt[1] = 1,rk += 1 * 1!,rk = 17。

  最后由于除第0位本身外已经没有数了,cnt[0]恒等于0。所以3 4 2 1的排名为18。

代码:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. using namespace std;
  5. int f[10], n;
  6. bool vis[10];
  7. int KtSplay(int *a) {  //康托展开,返回的[1, n!]之间的数
  8. int rk = 0;
  9. cal();
  10. for (int i = 1; i <= n; ++i)
  11. vis[i] = 0;
  12. for (int i = n - 1; i >= 0; --i) {
  13. int u = a[i], cnt = 0;
  14. for (int i = 1; i < u; ++i)
  15. if (!vis[i]) ++cnt;
  16. rk += cnt * f[i];
  17. vis[u] = true;
  18. }
  19. return rk + 1;
  20. }
  21. int a[10];
  22. int main() {
  23. cin >> n;
  24. for (int i = n - 1; i >= 0; --i)
  25. cin >> a[i];
  26. cout << KtSplay(a);
  27. }

(先咕掉逆展开)

(先补一点)

  康托展开的逆过程,就是依照排名来查询排列。

  首先把排名-1(突然发现这样有点麻烦,可能从0开始编排名号更合理,大家看得懂就好)。然后我们考虑康托展开的过程,用带余除法的方式确定每一位数字的排名,进而得到这个数。

  比如我们要计算{1, 2, 3, 4}排列中排第18的排列。

  第三位(最高位):17/3! = 2……5,说明比该位小的数有2个,该位是3。

  第二位:5/2! = 2……1,说明这一位是当前没出现的第2个,该位是4。

  第三位:1/1! = 1……0,说明这一位是2。

  那么最后一位是1。

  所以所求排列是3、4、2、1。

代码:

  1. void KtResplay(int rk) {
  2. --rk;
  3. cal();
  4. for (int i = n - 1; i; --i) {
  5. int k = rk / f[i];
  6. int j = 0;
  7. while (k >= 0) {
  8. ++j;
  9. if (!vis[j])
  10. --k;
  11. }
  12. vis[j] = true;
  13. a[i] = j;
  14. rk = rk % f[i];
  15. }
  16. for (int i = 1; i <= n; ++i)
  17. if (!vis[i]) {
  18. a[0] = i;
  19. break;
  20. }
  21. return;
  22. }

(2019.7.16 坑填了)

【数学】康托展开 && 康托逆展开的更多相关文章

  1. 康托展开&&康托逆展开

    康托展开 简介:对于给定的一个排列,求它是第几个,比如54321是n=5时的第120个.(对于不是1~n的排列可以离散化理解) 做法: ans=a[n]*(n-1)!+a[n-1]*(n-2)!+~~ ...

  2. HDU 1027 Ignatius and the Princess II(康托逆展开)

    Ignatius and the Princess II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ( ...

  3. 康托展开&康托逆展开 的写法

    康托展开 康托展开解决的是当前序列在全排序的名次的问题. 例如有五个数字组成的数列:1,2,3,4,5 那么1,2,3,4,5就是全排列的第0个[注意从0开始计数] 1,2,3,5,4就是第1个 1, ...

  4. nyoj 139——我排第几个|| nyoj 143——第几是谁? 康托展开与逆康托展开

    讲解康托展开与逆康托展开.http://wenku.baidu.com/view/55ebccee4afe04a1b071deaf.html #include<bits/stdc++.h> ...

  5. 康托展开&逆展开算法笔记

    康托展开(有关全排列) 康托展开:已知一个排列,求这个排列在全排列中是第几个 康托展开逆运算:已知在全排列中排第几,求这个排列 定义: X=an(n-1)!+an-1(n-2)!+...+ai(i-1 ...

  6. 康托展开+逆展开(Cantor expension)详解+优化

    康托展开 引入 康托展开(Cantor expansion)用于将排列转换为字典序的索引(逆展开则相反) 百度百科 维基百科 方法 假设我们要求排列 5 2 4 1 3 的字典序索引 逐位处理: 第一 ...

  7. 康托展开与逆康托展开模板(O(n^2)/O(nlogn))

    O(n2)方法: namespace Cantor { ; int fac[N]; void init() { fac[]=; ; i<N; ++i)fac[i]=fac[i-]*i; } in ...

  8. lightoj1060【康托逆展开】

    可以先看些资料:http://blog.csdn.net/keyboarderqq/article/details/53388936 参考谷巨巨:http://blog.csdn.net/azx736 ...

  9. 康托(Cantor)展开

    直接进入正题. 康托展开 Description 现在有"ABCDEFGHIJ”10个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的? Input ...

随机推荐

  1. js 重排和重绘

    1.什么是重排和重绘 浏览器下载完页面中的所有组件--HTML标记.JavaScript.CSS.图片之后会解析生成两个内部数据结构--DOM树和渲染树. DOM树表示页面结构,渲染树表示DOM节点如 ...

  2. npm ande gulp cmd

    在学习前,先谈谈大致使用gulp的步骤,给读者以初步的认识.首先当然是安装nodejs,通过nodejs的npm全局安装和项目安装gulp,其次在项目里安装所需要的gulp插件,然后新建gulp的配置 ...

  3. nb-iot技术实现跟踪功能的应用

    在互联网和连接的世界里,nb-iot风靡一时.企业和个人正在利用nb-iot技术和nb-iot设备的可靠,快速连接能力,对其技术系统进行渐进式更改,并创建一个互联的"智能"世界. ...

  4. ZOJ 1091 Knight Moves(BFS)

    Knight Moves A friend of you is doing research on the Traveling Knight Problem (TKP) where you are t ...

  5. docker容器与宿主机的数据交互

    在生产环境中使用 Docker ,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作. 方式一.Docker cp命令 docker cp :用于容器与主机之间 ...

  6. vim编辑器使用简介

    使用格式 vim [option] /path/to/somefile ... option: -o水平分割 -O垂直分割 +打开后在最后一行 +Num打开后在地Num行,加号与Num之间不能有空格 ...

  7. 云计算之路-出海记-小目标:Hello World from .NET 5.0 on AWS

    品尝过船上的免费晚餐,眺望着 aws 上搭建博客园海外站的宏伟目标,琢磨着眼前可以实现的小目标,不由自主地在屏幕上敲出了 -- "Hello World!",就从这个最简单朴实的小 ...

  8. Netty源码解析 -- ChannelOutboundBuffer实现与Flush过程

    前面文章说了,ChannelHandlerContext#write只是将数据缓存到ChannelOutboundBuffer,等到ChannelHandlerContext#flush时,再将Cha ...

  9. 最简单的基于FFmpeg的直播系统开发移动端例子:IOS 视频解码器

    本文记录IOS平台下基于FFmpeg的视频解码器.该示例C语言的源代码来自于<最简单的基于FFMPEG+SDL的视频播放器>.相关的概念就不再重复记录了. 源代码 项目的目录结构如图所示. ...

  10. 面向初学者的Python爬虫程序教程之动态网页抓取

    目的是对所有注释进行爬网. 下面列出了已爬网链接.如果您使用AJAX加载动态网页,则有两种方式对其进行爬网. 分别介绍了两种方法:(如果对代码有任何疑问,请提出改进建议)解析真实地址爬网示例是参考链接 ...