题目:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=2297

前置技能:(千万注意是从0开始数的

康托展开表示的是当前排列在n个不同元素的全排列中的名次。比如213在这3个数所有排列中排第3。

那么,对于n个数的排列,康托展开为:

其中表示第i个元素在未出现的元素中排列第几。举个简单的例子:

对于排列4213来说,4在4213中排第3,注意从0开始,2在213中排第1,1在13中排第0,3在3中排第0,即:

,这样得到4213在所有排列中排第ans=20

代码实现:(从0开始计数)

//康托展开  
LL Work(char str[])  
{  
    int len = strlen(str);  
    LL ans = 0;  
    for(int i=0; i<len; i++)  
    {  
        int tmp = 0;  
        for(int j=i+1; j<len; j++)  
            if(str[j] < str[i]) tmp++;  
        ans += tmp * f[len-i-1];  //f[]为阶乘  
    }  
    return ans;  //返回该字符串是全排列中第几大,从1开始  
}  

康托展开的逆运算:就是根据某个排列的在总的排列中的名次来确定这个排列。比如:

求1234所有排列中排第20的是啥,那么就利用辗转相除法确定康托展开中的系数,然后每次输出当前未出现过的第个元素。

代码实现康托展开逆运算:

//康托展开逆运算  
void Work(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 % f[i-1];  
        LL t = n / f[i-1];  
        n = r;  
        sort(v.begin(),v.end());  
        a.push_back(v[t]);  
        v.erase(v.begin()+t);  
    }  
    vector<int>::iterator it;  
    for(it = a.begin();it != a.end();it++)  
        cout<<*it;  
    cout<<endl;  
}  
Nine Digits
Time Limit: 3000 MS Memory Limit: 32768 K
Total Submit: 69(19 users) Total Accepted: 16(12 users) Rating:  Special Judge: No
Description
Input

多组数据,每组测试数据输入9个整数,为1-9的一个全排列。初始状态会被描述为

1 2 3 4 5 6 7 8 9

Output

输出所需要的最小移动步数。

Sample Input

1 2 3 4 5 6 7 8 9

9 8 7 6 5 4 3 2 1

Sample Output

0

12

那么对于这题,我们就暴力模拟,然后将状态数压缩到362880

就不用开10的9次幂那么大的数组了

具体实现如下,由于我为了方便用了string,于是常数被卡了,这题还是要用int表示状态快

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxn=362880;
char s[10];
int f[10];
int cantor(string s){
int ans=0;
for(int i=0;i<s.size();++i){
int tmp=0;
for(int j=i+1;j<s.size();++j)
if(s[i]>s[j]) tmp++;
ans+=tmp*f[s.size()-i-1];
}
return ans;
}
void LU(string &s){
char t[10];
t[0]=s[0];t[1]=s[1];t[3]=s[3];t[4]=s[4];
s[0]=t[3];s[1]=t[0];s[3]=t[4];s[4]=t[1];
}
void RU(string &s){
char t[10];
t[1]=s[1];t[2]=s[2];t[4]=s[4];t[5]=s[5];
s[1]=t[4];s[2]=t[1];s[4]=t[5];s[5]=t[2];
}
void LD(string &s){
char t[10];
t[3]=s[3];t[4]=s[4];t[6]=s[6];t[7]=s[7];
s[3]=t[6];s[4]=t[3];s[6]=t[7];s[7]=t[4];
}
void RD(string &s){
char t[10];
t[4]=s[4];t[5]=s[5];t[7]=s[7];t[8]=s[8];
s[4]=t[7];s[5]=t[4];s[7]=t[8];s[8]=t[5];
}
string temp[4];int step[maxn];bool vis[maxn];
void bfs(){
memset(step,-1,sizeof(step));
memset(vis,0,sizeof(vis));
queue<string> Q;Q.push(string(s));step[cantor(string(s))]=0;
string end=string("123456789");
while(Q.size()){
string now=Q.front();Q.pop();int nstate=cantor(now);
if(now.compare(end)==0) break;
for(int i=0;i<4;++i) temp[i]=now;
LU(temp[0]);RU(temp[1]);LD(temp[2]);RD(temp[3]);
for(int i=0;i<4;++i){
int state=cantor(temp[i]);
if(!vis[state]){
vis[state]=1;Q.push(temp[i]);step[state]=step[nstate]+1;
}
}
}
}
int a[10];
int main(){
f[1]=1;
for(int i=2;i<=9;++i){
f[i]=i*f[i-1];
}
while(~scanf("%d",a)){
for(int i=1;i<9;++i) scanf("%d",a+i);
for(int i=0;i<9;++i) s[i]=a[i]+'0';s[9]='\0';
bfs();
printf("%d\n",step[0]);
}
return 0;
}

附上AC题解http://blog.csdn.net/liangzhaoyang1/article/details/53471515

康托展开:对全排列的HASH和还原,判断搜索中的某个排列是否出现过的更多相关文章

  1. 用康托展开实现全排列(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)!+...+ ...

  2. OJ 1188 全排列---康托展开

    题目描述 求n的从小到大第m个全排列(n≤20). 输入 n和m 输出 输出第m个全排列,两个数之间有一空格. 样例输入 3 2 样例输出 1 3 2 #include<cstdio> # ...

  3. P3014 [USACO11FEB]牛线Cow Line && 康托展开

    康托展开 康托展开为全排列到一个自然数的映射, 空间压缩效率很高. 简单来说, 康托展开就是一个全排列在所有此序列全排列字典序中的第 \(k\) 大, 这个 \(k\) 即是次全排列的康托展开. 康托 ...

  4. 题解报告:NYOJ 题目139 我排第几个(康托展开)

    描述 现在有"abcdefghijkl”12个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的? 输入 第一行有一个整数n(0<n<=1 ...

  5. 题解 P5367 【【模板】康托展开】

    P5367 [模板]康托展开 感觉这题难度大概在绿题到蓝题之间qwq 一.洛谷日报[yummy]浅谈康托展开 如我想知道321是{1,2,3}中第几个小的数可以这样考虑 : 第一位是3,当第一位的数小 ...

  6. POJ 1077 Eight (BFS+康托展开)详解

    本题知识点和基本代码来自<算法竞赛 入门到进阶>(作者:罗勇军 郭卫斌) 如有问题欢迎巨巨们提出 题意:八数码问题是在一个3*3的棋盘上放置编号为1~8的方块,其中有一块为控制,与空格相邻 ...

  7. [算法总结]康托展开Cantor Expansion

    目录 一.关于康托展开 1.什么是康托展开 2.康托展开实现原理 二.具体实施 1.模板 一.关于康托展开 1.什么是康托展开 求出给定一个由1n个整数组成的任意排列在1n的全排列中的位置. 解决这样 ...

  8. LightOJ1060 nth Permutation(不重复全排列+逆康托展开)

    一年多前遇到差不多的题目http://acm.fafu.edu.cn/problem.php?id=1427. 一开始我还用搜索..后来那时意外找到一个不重复全排列的计算公式:M!/(N1!*N2!* ...

  9. HDU 1043 Eight (A* + HASH + 康托展开)

    Eight Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

随机推荐

  1. IDEA安装codota插件和使用,开发人员的知心伙伴

    打开IDEA 点击左上角的File之后,如下图 成功后如图所示

  2. SW3518中文规格书

    SW3518 是一款高集成度的多快充协议双口充电芯片, 支持 A+C 口任意口快充输出, 支持双口独立限流. 其集成了 5A 高效率同步降压变换器, 支持 PPS/PD/QC/AFC/FCP/SCP/ ...

  3. matlab gui matlab gui 鼠标点击显示图像颜色值

    首先看看效果 ‍ 首先功能说明下,运行后通过myfile菜单打开一幅图片之后在axes中显示,由于要使用图片的放大缩小等功能将figure 的菜单栏与工具栏都一并打开了. 界面编程主要是callbac ...

  4. JMeter去掉启动的cmd命令窗口和制作快捷方式

    1.去掉启动的cmd命令窗口 在使用jmeter时,如果使用默认的jmeter.bat启动的话,会出现一个CMD命令窗口,之后才会启动jmeter工作界面: 如果直接启用ApacheJMeter.ja ...

  5. ArchLinux安装后所需要的环境和工具

    ArchLinux安装后所需要的环境和工具 工具: Dolphin 文件管理器 ntfs-3G 移动硬盘挂载 octopi 实时检查更新 KDE Connect 手机电脑远程连接 DBeaver Co ...

  6. Linux内核[CVE-2016-5195] (dirty COW)原理分析

    [原创]Linux内核[CVE-2016-5195] (dirty COW)原理分析-二进制漏洞-看雪论坛-安全社区|安全招聘|bbs.pediy.com https://bbs.pediy.com/ ...

  7. circus reload

    circus reload Configuration - Circus 0.15.0 documentation https://circus.readthedocs.io/en/latest/fo ...

  8. KMP算法 字符串匹配(看猫片)

    前言 此篇笔记根据自己的理解和练习心得来解释算法,只代表个人观点,如有不足请指出(我刚学QWQ) 浅谈字符串匹配 设想一个场景,假设你是一个净化网络语言环境的管理员,每天需要翻阅大量的文章和帖子来查找 ...

  9. 【译】Async/Await(四)—— Pinning

    原文标题:Async/Await 原文链接:https://os.phil-opp.com/async-await/#multitasking 公众号: Rust 碎碎念 翻译 by: Praying ...

  10. hadoop知识点总结(二)hdfs分布式文件系统

    1, hdfs设计:减少硬件错误的危害,流式数据访问,大规模数据集,简单的一致性模型 2,特点: 1)移动计算的代价比移动数据的代价低 在异构的软硬件平台间的可移植性 2)局限性 不适合低延迟性数据访 ...