康托展开:对全排列的HASH和还原,判断搜索中的某个排列是否出现过
题目: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 | ||||||
|
||||||
| 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和还原,判断搜索中的某个排列是否出现过的更多相关文章
- 用康托展开实现全排列(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)!+...+ ...
- OJ 1188 全排列---康托展开
题目描述 求n的从小到大第m个全排列(n≤20). 输入 n和m 输出 输出第m个全排列,两个数之间有一空格. 样例输入 3 2 样例输出 1 3 2 #include<cstdio> # ...
- P3014 [USACO11FEB]牛线Cow Line && 康托展开
康托展开 康托展开为全排列到一个自然数的映射, 空间压缩效率很高. 简单来说, 康托展开就是一个全排列在所有此序列全排列字典序中的第 \(k\) 大, 这个 \(k\) 即是次全排列的康托展开. 康托 ...
- 题解报告:NYOJ 题目139 我排第几个(康托展开)
描述 现在有"abcdefghijkl”12个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的? 输入 第一行有一个整数n(0<n<=1 ...
- 题解 P5367 【【模板】康托展开】
P5367 [模板]康托展开 感觉这题难度大概在绿题到蓝题之间qwq 一.洛谷日报[yummy]浅谈康托展开 如我想知道321是{1,2,3}中第几个小的数可以这样考虑 : 第一位是3,当第一位的数小 ...
- POJ 1077 Eight (BFS+康托展开)详解
本题知识点和基本代码来自<算法竞赛 入门到进阶>(作者:罗勇军 郭卫斌) 如有问题欢迎巨巨们提出 题意:八数码问题是在一个3*3的棋盘上放置编号为1~8的方块,其中有一块为控制,与空格相邻 ...
- [算法总结]康托展开Cantor Expansion
目录 一.关于康托展开 1.什么是康托展开 2.康托展开实现原理 二.具体实施 1.模板 一.关于康托展开 1.什么是康托展开 求出给定一个由1n个整数组成的任意排列在1n的全排列中的位置. 解决这样 ...
- LightOJ1060 nth Permutation(不重复全排列+逆康托展开)
一年多前遇到差不多的题目http://acm.fafu.edu.cn/problem.php?id=1427. 一开始我还用搜索..后来那时意外找到一个不重复全排列的计算公式:M!/(N1!*N2!* ...
- HDU 1043 Eight (A* + HASH + 康托展开)
Eight Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
随机推荐
- 【高并发】ReadWriteLock怎么和缓存扯上关系了?!
写在前面 在实际工作中,有一种非常普遍的并发场景:那就是读多写少的场景.在这种场景下,为了优化程序的性能,我们经常使用缓存来提高应用的访问性能.因为缓存非常适合使用在读多写少的场景中.而在并发场景中, ...
- 特征预处理之归一化&标准化
写在前面 这篇博客的主要内容 应用MinMaxScaler实现对特征数据进行归一化 应用StandardScaler实现对特征数据进行标准化 特征预处理 定义 通过一些转换函数将特征数据转换成更加 ...
- Go - httpclient 常用操作
httpclient 模块介绍 httpclient 是基于 net/http 封装的 Go HTTP 客户端请求包,支持常用的请求方式.常用设置,比如: 支持设置 Mock 信息 支持设置失败时告 ...
- 提取一个int类型数最右侧的1
提取一个int类型数最右侧的1 算法描述 把一个int类型的数,提取出最右侧的1来,例如: 6 对应的二进制位 0000 0110,那么取出来的应该是0000 0010 算法思路 对原数0000 01 ...
- Java并发组件三之Semaphore
使用场景:常用于使用有限的资源,限制线程并发的最大数量.默认情况下,信号量是非公平性的(先等待先执行为公平.类似于买东西的时候大家排队付款,先来的先付款是公平的.但是这时候有人插队,那就是非公平的)设 ...
- 目前 c++ primer学习总结笔记
C++的开始 1 main的返回值:0为成功状态,非0为系统定义的错误类型 2 输入输出:计算结果为左侧运算对象,IO操作读写缓冲与程序中的动作无关 3 输入流istream对象:cin(标准输入): ...
- Java 从Character和char的区别来学习自动拆箱装箱
本文结构 1.Character和char 的区别: 2.自动拆箱装箱 1.Character和char 的区别: Character是类,char基本数据类型. 在java中有三个类负责对字符的操作 ...
- CF1190B
扯在前面 我们老师刚讲过的题目,很考验思维,本蒟蒻WA了十发才过,然后看到题解里只是指出了特殊情况没多解释,可能有人看不懂,特来分享一下 首先题目就很有意思,思考的过程也很有趣,想把所有情况思考全思考 ...
- Spark练习之action操作开发
Spark练习之action操作开发 一.reduce 1.1 Java 1.2 Scala 二.collect 2.1 Java 2.2 Scala 三.count 3.1 Java 3.2 Sca ...
- docker --- (入门必读)
容器 容器就是一个视图隔离.资源可限制.独立文件系统的进程集合.所谓"视图隔离"就是能够看到部分进程以及具有独立的主机名等:控制资源使用率则是可以对于内存大小以及 CPU 使用个数 ...


