题目: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. Vue的核心思想

    Vue的核心思想主要分为两部分: 1.数据驱动  2.组件系统 1.数据驱动 在传统的前端交互中,我们是通过Ajax向服务器请求数据,然后手动的去操作DOM元素,进行数据的渲染,每当前端数据交互变化时 ...

  2. 【故障公告】K8s CofigMap 挂载问题引发网站故障

    今天凌晨我们用阿里云服务器自建的 kubernetes 集群出现突发异常情况,博客站点(blog-web)与博客 web api(blog-api)的 pod 无法正常启动(CrashLoopBack ...

  3. Spring-01-事务

    Spring事务机制 spring事务机制最重要的两个配置项,隔离级别和传播特性. 1. 隔离级别 隔离级别针对高并发问题导致的数据库丢失更新问题 1.1 数据库的4大基本特征 原子性(Atomic) ...

  4. selenium八大元素定位方法

    1.ID定位 可以根据元素的id来定位属性,id是当前整个HTML页面中唯一的,所以可以通过id属性来唯一定位一个元素,是首选的元素定位方式.(动态ID不做考虑) # 导入webdriver和By f ...

  5. WireShark 之 text2pcap

    前言 本来想用 010Editer 的,看到破解教程头都大了,那么就用 WireShark 的 Text2pcap 吧! 正文 打开CMD控制台窗口,转到WireShark安装目录 ,此处可以shif ...

  6. 如何在opencv下使用SIFT

    SIFT即尺度不变特征变换,是用于图像处理领域的一种描述.这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征描述子.SIFT的尺度不变特征变换在图像特征点匹配中十分关键,因为我们从不同角度 ...

  7. HDU1814和平委员会

    题目大意: 有n对的人,编号从1-2*n,m对的人之间互相不喜欢,每对人中必徐选1个人加入和平委员会,求字典序最小的解 -------------------------------- 2-SAT问题 ...

  8. ThinkPHP 5.0.24 反序列化RCE (Windows下EXP)

    直接上exp吧,Windows下. <?php namespace think\process\pipes; class Windows { private $files = []; publi ...

  9. 通过jenkins构建服务,并发布服务,修改Jenkins以Root用户运行

    通过jenkins构建服务,并发布服务,修改Jenkins以Root用户运行 其他博文:从0到1体验Jenkins+Docker+Git+Registry实现CI自动化发布 Jenkins注册中心 一 ...

  10. Mac变卡顿,优化性能

    当调整窗口大小,同时按住"Option"键,可以从中央调整大小 同时按住"Shift"键时,可以按比例调整大小.同时按住这两个键,那么既成比例,又从中央调整大小 ...