康托展开:对全排列的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 ...
随机推荐
- Java开发工具类集合
Java开发工具类集合 01.MD5加密工具类 import java.security.MessageDigest; import java.security.NoSuchAlgorithmExce ...
- Flink的状态与容错
本文主要运行到Flink以下内容 检查点机制(CheckPoint) 状态管理器(StateBackend) 状态周期(StateTtlConfig) 关系 首先要将state和checkpoint概 ...
- 网络流量预测入门(二)之LSTM介绍
目录 网络流量预测入门(二)之LSTM介绍 LSTM简介 Simple RNN的弊端 LSTM的结构 细胞状态(Cell State) 门(Gate) 遗忘门(Forget Gate) 输入门(Inp ...
- pip freeze 需求文件requirements.txt的创建及使用 虚拟环境
总结: 1.输出安装的包信息,并在另一个环境快速安装 Generate output suitable for a requirements file. $ pip freeze docutils== ...
- 网络编程中 TCP 半开连接和TIME_WAIT 学习
https://blog.csdn.net/chrisnotfound/article/details/80112736 上面的链接就是说明来 SO_KEEPALIVE 选项 为什么还需要 在应用层开 ...
- vue项目在IE下报 [vuex] vuex requires a Promise polyfill in this browser错误
ie浏览器下报错 vue刚搭建的项目,在谷歌浏览器能够正常访问,但是在ie11等ie浏览器下无法显示页面,打开控制台查看无报错信息,打开仿真一栏,提示[vuex] vuex requires a Pr ...
- 设计模式c++(1)
本来是想把之前的<head first设计模式>看了,不过因为这本书是java实现的,跟c++还是略有区别. 于是找了一下,发现了一个不错的blog,打算连书带blog一起参考着看了. b ...
- Birkhoff-von Neumann Crossbar 光交换网络的调度方案
Birkhoff-von Neumann Crossbar 光交换网络的调度方案 This is a summary aimed at looking for "high perform ...
- BZOJ 4516. [Sdoi2016]生成魔咒【SAM 动态维护不同子串数量】
[Sdoi2016]生成魔咒 动态维护不同子串的数量 想想如果只要查询一次要怎么做,那就是计算各个点的\(len[u]-len[link[u]]\)然后求和即可,现在要求动态更新,我们可以保存一个答案 ...
- 【POJ 2411】【Mondriaans Dream】 状压dp+dfs枚举状态
题意: 给你一个高为h,宽为w的矩阵,你需要用1*2或者2*1的矩阵填充它 问你能有多少种填充方式 题解: 如果一个1*2的矩形横着放,那么两个位置都用二进制1来表示,如果是竖着放,那么会对下一层造成 ...


