[ZJOI2005]九数码游戏(BFS+hash)

Solution
这题的话直接上BFS就可以了,因为要输出方案,所以我们要开一个pre数组记录前驱,最后输出就可以了。
对于状态的记录,一般都用哈希来存,但因为这道题比较特殊,它是一个排列,所以我们可以利用康拓展开把空间压到9!。
康拓展开
一个排列的康拓展开表示的是字典序比他小的排列的个数,所以我们统计一下每一位后面有几个比它小的数字,乘上(n-i)!
inline int zx_hash(int x){
for(int i=;i>=;--i)a[i]=x%,x/=;
int num=;
for(int i=;i<=;++i){
int aa=;
for(int j=i+;j<=;++j)if(a[i]>a[j])aa++;
num+=aa*jie[-i];
}
return num;
}
逆康拓展开
我们不但要支持把排列映射成数字,还要支持把数字映射成排列。
具体操作就是从高到低按位考虑,令x=num/(n-i)!,那么可选集合中有x个数是比这一位上的数字小的,所以我们选择第x+1个数。
inline int anti_hash(int x){
int num=;
for(int i=;i<=;++i)vec[i]=i;int zo=;
for(int i=;i>=;--i){
int y=x/jie[i];
x=x%jie[i];
num=num*+vec[y];
for(int j=y;j<zo;++j)vec[j]=vec[j+];zo--;
}
return num;
}
不过康拓展开的复杂度是n^2的,但常数较小,遇到哈希排列之类的问题试一下。
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<algorithm>
#define mm make_pair
#define N 12
using namespace std;
const int r1[]={,,,,,,,,,};
const int r2[]={,,,,,,,,,};
int jie[N],a[N],d1[N],d2[N],x,win,ans[],ji[],tag,tot,vec[];
struct node{
int first,second;
};
queue<node>q;
inline int zx_hash(int x){
for(int i=;i>=;--i)a[i]=x%,x/=;
int num=;
for(int i=;i<=;++i){
int aa=;
for(int j=i+;j<=;++j)if(a[i]>a[j])aa++;
num+=aa*jie[-i];
}
return num;
}
inline int anti_hash(int x){
int num=;
for(int i=;i<=;++i)vec[i]=i;int zo=;
for(int i=;i>=;--i){
int y=x/jie[i];
x=x%jie[i];
num=num*+vec[y];
for(int j=y;j<zo;++j)vec[j]=vec[j+];zo--;
}
return num;
}
int main(){
for(int i=;i<=;++i)scanf("%d",&a[i]),x=x*+a[i];jie[]=;int mem=x;
for(int i=;i<=;++i)jie[i]=jie[i-]*i;
win=zx_hash();
q.push(node{zx_hash(x),});
while(!q.empty()){
int u=q.front().first,nn=q.front().second;q.pop();
if(u==win){
printf("%d\n",nn);
tag=;
break;
}
x=anti_hash(u);
for(int i=;i>=;--i)d1[r1[i]]=x%,d2[r2[i]]=x%,x/=;
int x1=,x2=;
for(int i=;i<=;++i)x1=x1*+d1[i],x2=x2*+d2[i];
x1=zx_hash(x1);x2=zx_hash(x2);
if(!ji[x1])ji[x1]=u,q.push(node{x1,nn+});
if(!ji[x2])ji[x2]=u,q.push(node{x2,nn+});
}
if(!tag){
printf("UNSOLVABLE");
return ;
}
x=mem;x=zx_hash(x);
while(win!=x){
ans[++tot]=win;win=ji[win];
}
ans[++tot]=x;
for(int i=tot;i>=;--i){
int qq=anti_hash(ans[i]);
for(int j=;j>=;--j)a[j]=qq%,qq/=;
printf("%d %d %d\n%d %d %d\n%d %d %d\n\n",a[],a[],a[],a[],a[],a[],a[],a[],a[]);
}
return ;
}
[ZJOI2005]九数码游戏(BFS+hash)的更多相关文章
- [ZJOI2005]九数码游戏
[ZJOI2005]九数码游戏 题目描述 输入输出格式 输入格式: 输入文件中包含三行三列九个数,同行的相邻两数用空格隔开,表示初始状态每个方格上的数字.初始状态不会是目标状态. 输出格式: 如果目标 ...
- 洛谷 P2578 [ZJOI2005]九数码游戏【bfs+康托展开】
只有9!=362880个状态,用康托展开hash一下直接bfs即可 #include<iostream> #include<cstdio> #include<cstrin ...
- LG2578 「ZJOI2005」九数码游戏 bfs
问题描述 LG2578 题解 用string+map去重. bfs即可. \(\mathrm{Code}\) #include<bits/stdc++.h> using namespace ...
- 洛谷 - P2578 - 九数码游戏 - bfs
https://www.luogu.org/problemnew/show/P2578 一个挺搞的东西,用康托展开做记忆化搜索可以少一个log的查询. #include <bits/stdc++ ...
- 万圣节后的早晨&&九数码游戏——双向广搜
https://www.luogu.org/problemnew/show/P1778 https://www.luogu.org/problemnew/show/P2578 双向广搜. 有固定起点终 ...
- HDU-1043 Eight八数码 搜索问题(bfs+hash 打表 IDA* 等)
题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原 ...
- 【BZOJ】1054: [HAOI2008]移动玩具(bfs+hash)
http://www.lydsy.com/JudgeOnline/problem.php?id=1054 一开始我还以为要双向广搜....但是很水的数据,不需要了. 直接bfs+hash判重即可. # ...
- C#_界面程序_数码游戏
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- [BZOJ1054][HAOI2008]移动玩具 bfs+hash
1054: [HAOI2008]移动玩具 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2432 Solved: 1355[Submit][Stat ...
随机推荐
- Drools 规则引擎
Drools - Drools - Business Rules Management System (Java™, Open Source) http://drools.org/ [Drools]J ...
- Nginx会话保持之nginx-sticky-module模块
Nginx会话保持之nginx-sticky-module模块 - 天行健,君子以自强不息:地势坤,君子以厚德载物. - CSDN博客https://blog.csdn.net/huangjinjin ...
- CentOS 7 安装配置带用户认证的squid代理服务器
这里只简述搭建一个带用户认证的普通代理 一.安装 安装过程十分简便,只需要安装一下squid,一条命令搞定 yum install squid rpm -qa | grep squid squid-- ...
- Sqlserver 命令行方式修改 用户密码的方法
1. 之前写了一个 可以使用 ssms 的方式修改密码的情况 2. 还有办法是执行命令 exec sp_password null,'newpassword','sa' # sa 是用户名 newp ...
- 工程下CmakeLists.txt
2.工程下Cmake 本小节的任务是让上一小结的程序更像一个工程: 为工程添加一个子目录 src,用来放置工程源代码 : 添加一个子目录doc,用来放置这个工程的文档 hello.txt: 在工程目录 ...
- vue小问题库
引入vue组件命名时,不用特殊标签,比如<head>,不然会按特殊标签处理
- mac下virtualbox中centos6.5虚拟机实现全屏和调整分辨率
在visualbox里安装好centos后,发现不能分辨率与原屏幕不一致,很多解决方法是:安装增强包.可是安装增强包后依然达不到效果. 究其原因,原来因为没有安装显卡驱动导致安装了增强包后无法实现分辨 ...
- html 引入页面公共部分(header、footer)
html引入页面的公共部分,比如导航栏啊,页头页脚之类的. 1.将需要引入的公共html部分转换为js文件,这里推荐一个转换工具地址 http://tool.chinaz.com/Tools/Html ...
- MySQL 单个表锁死 对查询语句无响应
这个时候应该怀疑读取都被加锁,应该尝试使用 show processlist 查看每一个正在运行的进程. 可以看到这样一个列表,里面有使用者即用户,正在使用数据库的 host, 使用的 db 目前的 ...
- 996.ICU
996.ICU https://github.com/996icu/996.ICU https://www.zhihu.com/question/317722302 LICENSE https://g ...